Detect Browser Refresh vs. Form Submit in ASP.Net MVC 2 - asp.net-mvc-2

I have an ASP.Net questionnaire application that resubmits data to the same page, showing a different question each time. There are BACK and NEXT buttons to navigate between questions.
I would like to detect when the form is submitted due to a browser refresh vs. one of the buttons being pressed. I came across a WebForms approach but don't know how to apply those principals in an MVC 2 application since page events aren't available (as far as I know... I'm pretty new to Microsoft's MVC model).
How would one apply that principle to MVC 2? Is there a better way to detect refresh?

You could use the redirect-after-post pattern with TempData. Example:
The Back and Next buttons POST a form to a controller action
The controller action puts some state into the TempData and redirects to another controller action which will verify that the data is in TempData and return the view
The user presses F5 on the browser, the previous action is called on GET and as the state is no longer into TempData you know the user pressed F5 and didn't pass through the form submission.
And to illustrate this:
public class HomeController: Controller
{
public ActionResult Index()
{
var state = TempData["state"];
if (state == null)
{
// the user directly arrived on this action without passing
// through the form submission
}
return View();
}
[HttpPost]
public ActionResult Index(string back)
{
TempData["state"] = new object();
return RedirectToAction("Index");
}
}

Related

Multiple forms in ASP.NET Core Razor Page, one in a modal

I am using the new ASP.NET Core Razor Pages. I have a standard login form on the page; works fine. I want to add a second form in a modal dialog on the page (forgot my password). When the user submits the modal form, I want to manually submit the form and show a message on the modal (the user then clicks close on the modal). Maybe I can't do a standard form, but was hoping to somehow leverage all the model binding and validation that comes in a Razor Page.
Any ideas on how to set up the form in the modal, submit the "forgot my password" request to the server, then display a message in the modal?
I use ajax for that case
$.getJSON("/Contact?handler=CreateNewsLetters", {"email" : email })
.done(function(data, textStatus, jqXHR) {
let modal = $("#modalFinish");
let paError = '<p>Done! <p>';
modal.find(".modal-body").html(paError);
modal.modal("show");
});
Contact.cshtml.cs
public ActionResult OnGetCreateNewsLetters(string email)
{ return new JsonResult(email); }

Can we just let "prepareFromRequest" to behave just like traditional non-Ajax page?

Ok, let see how traditional non-Ajax page work. Suppose you have a page like the below link
abc.com#!search;item=car
In the traditional non-Ajax website, when first time you call "abc.com#!search;item=car", it will go to server and get data. After that you go to other page like "abc.com#!customer;name=tom" and then you hit back button it will go back to "abc.com#!search;item=car". However, this time it won't call to the server again cos it remembered it did before.
Now Here is the GWTP problem. Suppose the above abc.com was built in GWTP technology.
At the first time wen user enters the "abc.com#!search;item=car", the GWTP app will initialize the page "search" via onBind, then the prepareFromRequest will be called & it will go to server to get data.
That is Good, no problem. However, if we open a new page (like customer page) by using revealPlace, then we hit the back button it will go back to "search" page & it will call prepareFromRequest again. The prepareFromRequest will then make the exactly same call to server again. That is not good cos it wastes resource.
So I want the "prepareFromRequest" to be called ONLY at the time we initialise the page (run after onBind) & block the "prepareFromRequest" in all other page request (ex like user press the back button).
It mean "prepareFromRequest" should work just like traditional non-Ajax page mentioned above.
Can we do that? or
Do you have a better solution?
Why don't you just check in your prepareFromRequest method if you have already a search result for that specific searchterm and only issue a call to the backend if it has changed?
Something like this:
public Presenter extends .... {
String searchItem = null;
List<DTO> searchResult = null;
#Override
public void prepareFromRequest(PlaceRequest placeRequest) {
super.prepareFromRequest(placeRequest);
String item = placeRequest.getParameter("item",null));
if (searchItem == null || !searchItem.equals(item)) {
searchItem = item;
// MAKE A CALL TO THE BACKEND AND STORE THE DATA IN A FIELD.
searchResult = GET_FROM_SERVER(searchItem);
}
}
}

Using GWTs activities and places can I navigate to a previous page without using History.back()?

I am using GWTs Activities and Places pretty much as described on http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html and it is all working fine.
What I would like to do is from a particular page navigate to the previous page without using History.back() as I don't want to lose the history state. (I have a page where the user performs an action, on success I want to return to the previous page and keep the history state, on the other hand if they cancel I do want to use History.back() as I do want to lose the state).
The only way I can think of to do this is to create my own Place/History tracking code that listens to Place/History change events and makes the previous Place available to me so that I can call placeController.goto(...)
Is there an easier way of doing this? Am I missing something?
The approach I took was to store the history token in code (as suggested). I extended PlaceController and used it to track Place changes on the EventBus. Now everywhere I was using PlaceController I instead use PlaceControllerExt which has a nice previous() method that takes me back to where I came from - but navigates forward and never leaves the application.
public class PlaceControllerExt extends PlaceController {
private final Place defaultPlace;
private Place previousPlace;
private Place currentPlace;
public PlaceControllerExt(EventBus eventBus, Place defaultPlace) {
super(eventBus);
this.defaultPlace = defaultPlace;
eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
public void onPlaceChange(PlaceChangeEvent event) {
previousPlace = currentPlace;
currentPlace = event.getNewPlace();
}
});
}
/**
* Navigate back to the previous Place. If there is no previous place then
* goto to default place. If there isn't one of these then it'll go back to
* the default place as configured when the PlaceHistoryHandler was
* registered. This is better than using History#back() as that can have the
* undesired effect of leaving the web app.
*/
public void previous() {
if (previousPlace != null) {
goTo(previousPlace);
} else {
goTo(defaultPlace);
}
}
}
You have to somehow keep track of were to return, because instead of cancel the user can hit the back button, which would be the same as clicking cancel, except there is no code in your application executed, so you have no control.
Secondly if you have the history in the url, the user could navigate directly to that page and then you should know where to go to when the user click ok. Or if the user goes directly to the page, redirect the user to another page.
One approach is to store the return history token in the history token of the page you go to. When the page is finished it can go back(or technically it would be 'go forward') to that page based on the passed return token. (Although with GWT you could easily store the history token in code).

mvc2 - getting the URL to reflect the form submission

I have an MVC2 application with a form (like ya do). The user enters a query into the form (in the /Cars/Index view) and hits the "submit" button which posts to the Details action of CarsController - the Details view renders with results, and all is well and good.
The user can enter a URL (such as /Cars/Details/123-125) and they get the Details view with 123, 124 and 125 displayed, same as if you'd entered it on the form. Also well and good.
What I want to enable, if possible, is that when the user enters "123-125" or whatever in the form the URL also reflects the results - instead of "/Cars/Details" for a URL, which is what shows now, I want it to show "/Cars/Details/123-125".
For the life of me, I cannot figure out how this should be done.
Any assistance is appreciated.
Change your form to a GET instead of POST method (POST is the default), and it should just work.
<% using (Html.BeginForm("Action", "Controller", FormMethod.Get)) { %>
It sounds like its not finding a matching route definition for /Cars/Details/123-125. I think this could be happening because of the way the routing engine works.
ASP.NET MVC Route Contraints with {ID}-{Slug} Format
Ok, here is the answer I came up with:
In short: Redirect to GET
Basically, I write an action with [HttpPost] Attribute that redirects the form submittal to another action with [HttpGet] attribute. The route works whether you submit the form or type in the URL manually.
[HttpPost]
public ActionResult Details(CarViewModel model, int? pageNbr) {
// simply takes the form POST and re-routes it as a GET to pretty up the URL
// (see second Details action)
int page = pageNbr ?? 0;
return RedirectToAction("Details", new { query = model.Query, pageNbr = page });
}
[HttpGet]
public ActionResult Details(CarViewModel model, int pageNbr)
{
// various magic to create the view...
return View(avm);
}
As an added bonus, this takes care of the "Are you sure you want to resubmit?" annoyance when someone refreshes the page or hits the BACK button in their browser.

ASP.NET Button Click event does not appear to fire

I'm relatively new to ASP.NET. I have a ASP.NET MVC 2 Web Application project (created in Visual Studio 2010). I added a method to HomeController called Search
public ActionResult Search()
{
return View();
}
and created a corresponding view (web page) called Search.aspx onto which I dropped a button. I double-clicked the button to add a handler for the button click event which sets the text of a TextBox, then built the application.
<script runat="server">
protected void MyButton1_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Undo button clicked");
m_search_text_box.Text = "MyButton1_Click";
}
...
When I click the button in my browser (I tested in Chrome and Internet Explorer), nothing happens. The text box is not updated. Nothing is written to the Output window either. So, it doesn't look like the event is firing. Can anybody offer any suggestions? I'm using Visual Studio 2010 on Windows 7.
Thanks
You are mixing WebForms event handling into an MVC app. MVC does not work like WebForms. Check out the tutorials on MVC2 to help get you started down the right path.
Here's a sample app with step by step tutorials to help get to the basics of MVC down.
ASP.NET MVC doesn't use code behind handlers like that. You use controller actions to respond to requests, and decide how to visually handle them (ie: you can render a view, or return a JSON object, or redirect to another Action etc).
In your instance, if you want to put some text in a textbox after the user has clicked the button, you'd want to put a Submit button in a form, and create a controller action to respond to it:
[HttpPost]
public ActionResult Search()
{
var model = new SearchModel();
model.StatusText = "MyButton1_Click";
return View(model);
}
In your view, you want to use this model, and put its StatusText property value into a textbox:
<%= Html.TextBoxFor(x => x.StatusText) %>
Have a look at the ASP.NET MVC website which has a lot of great getting started tutorials, and the Nerd Dinner tutorial (a free chapter in the book).