How can I prevent form resubmission in MVC - c#

My current situation is as follows.
I have a form that when it gets submitted, passes the model into the controller and it does what it needs to do. At the end it redirects to a confirmation page that also gets passed the same model. All of that works fine, except when I am on the confirmation page, whenever I reload the page it resubmits the form.
I've tried using TempData but when I use that it requires for my model to be serializable and my model uses other models inside it that were made by other people that all need to be serializable which would result in like 15-20 different classes all needing to become serializable which just doesnt seem reasonable.
Here is some of what I am working with:
[HttpPost]
public async Task<ActionResult> SubmitClaim(WarrantyClaim model)
{
... code ...
return BeddingWarrantyConfirmation(model);
}
public ActionResult BeddingWarrantyConfirmation(WarrantyClaim model)
{
return View("BeddingWarrantyConfirmation",model);
}

You could make use of the Post Redirect Get Pattern. You could return the following in SubmitClaim:
return RedirectToAction("BeddingWarrantyConfirmation", "CONTROLLER", model);
For more information, please see https://en.wikipedia.org/wiki/Post/Redirect/Get

This is a common problem in MVC development, you can follow the Post/Redirect/Get strategy to avoid the request.
https://en.wikipedia.org/wiki/Post/Redirect/Get

Related

How to call a function in the controller from the view using ASP.NET MVC C# Html

I am trying to do a simple connection between the view and the controller. I have a button in the view
<button value="submit" onclick="location.href='#Url.Action("submit", "Home")'" >Submit</button>
and I have the controller function here
public ActionResult submit()
{
Console.WriteLine("hello test");
return View();
}
When I debug it calls the function, but when it goes through it results in an unhandled exception.
I am still new to this and have not found a simple way to call a function on the controller from the view that will not try to change to a new page. Thank you for any help.
If you use
return View();
in controller method you need to be sure that you have a .cshtml view file.
In your case I think you need to add submit.cshtml file.
Your error is most likely caused because you
A: don't have a view called submit, and since you are not naming a view in the controller return it is looking for a view it cannot find
or
B: you are not returning a view model which the view is expecting, posting up the exception you are getting will make it easier to help with this!
you will need to use java script to achieve what you want to. There is no way to call a function in a controller without causing a page refresh, even if you do not return a view, or return the same view it will end up doing a full page refresh.
You need to look into using an asynchronous java script call like the fetch() A.P.I. this will allow you to trigger methods in the controller and then you can return the results of this method as json, or by rerendering a partial view. Unless I have misunderstood what you are trying to achieve!

In ASP.NET MVC 5, how does the framework knows that a POST request comes from its own webpage?

Allow me to explain in more detail.
I've been learning and testing around with ASP.NET's MVC 5 using Visual Studio 2017. From what I understand, a Controller's "Actions" or methods are mapped according to a route format in "RouteConfig.cs", making all public methods accessible to web requests.
In the case of a simple GET method that returns a View, like this one:
// GET: Movies/Create
public ActionResult Create()
{
return View();
}
I would only need to enter the correct URL and I have obtained the View.
But in the case of sensible POST actions like deleting a data-entry, how does the controller make sure that the POST request is a valid one that comes from one of its own Views, instead of an unknown webpage? With the assumption that an action only need to be mapped to a matching route to be called.
Using a code sourced from one of Microsoft's tutorials as an example:
public class MoviesController : Controller
{
private MovieDBContext db = new MovieDBContext();
/*
Bunch of Other GET Actions
*/
// POST: Movies/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Movie movie = db.Movies.Find(id);
db.Movies.Remove(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
/*
Bunch of Other GET Actions
*/
}
How does this Controller achieve this? If not, how can it be achieved?
That's the purpose of the Anti-Forgery token, which you're validating by decorating the action method with the ValidateAntiForgeryToken attribute. Your view will need to include an anti-forgery token to be validated via the #Html.AntiForgeryToken() HtmlHelper method
Based on your example, ValidateAntiForgeryToken will do this job.
If a bit more explanation, MVC has its own disciplined that once you create a new controller which name is "MyTest", naming convention is MyTestController. It means if you create a view for MyTest controller, a folder with MyTest should be created under View and where MyTest's views are supposed to be kept.
I hope you would get my explanation.
Enjoy coding !

What's the correct code to use View like a redirect?

One of the View methods on the Controller class (in System.Web.Mvc) allows you pass a model to a different view. However, it does not update the url to the name of the new view because this method works more like Server.Tranfer than Response.Redirect. The point is that this behaviour can be confusing to anyone picking-up MVC. So, after the View method has been called, I would like the url path to be rewritten to reflect the name of the new view. I have tried the following, which does not work, on a class that implements the Controller class:
public ViewResult ViewAsRedirect(string viewName, object model)
{
var baseView = base.View(viewName, model);
ControllerContext.HttpContext.RewritePath(baseView.ViewName);
return baseView;
}
What's the correct code to implement what I have described?
EDIT
Any RedirectToAction method does not allow you to send you model to another action. There is a dirty workaround where you store it in TempData before you exit one action and retrieve it at the beginning of another action. I don't want to use this pattern. This is why I am using View(...) instead.
You simply cannot "update the URL" (i.e. redirect) and return content.
If you want the new URL to show the same content as you anticipated, then you'll need to (temporarily) store the results and include an identifier for the resource that you wish to display on the redirected URL.
There you can pull the resource in from the controller for the redirected URL again, and display it on the appropriate view.
So if you POST your object model to /Foo/Create, you can for example store model in a database, which yields an ID: 42. Then you can redirect to /Foo/View/42, and display it.
If you can explain what you are actually trying to do, a more concrete answer can be given.
RedirectToAction is very intuitive in my opinion... you should use one of the redirecting methods of MVC controller: Redirect(url), RedirectToAction(acion), RedirectToAction(acion, controller), and so on.
example
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
public ActionResult Redirect()
{
return this.RedirectToAction("Index");
}
}
EDIT
If your action needs to collect tons of data to pass to the view, you could redirect very early, by detecting the condition of redirection, and loading all the data inside the other action, based on simple route data such as database IDs, or simple strigs or numbers.
== OR ==
You can render javascript code to change the URL in the client side, when the page loads: Modify the URL without reloading the page
This works only in very recent browsers (current date nov/2013).

ASP.NET MVC Controller return view model clarification

The following are two examples of a controller for submitting data. One returns the input model if validation fails the other doesn't. Can someone enlighten me on which is method correct or preferred? They seem to behave exactly the same.
With returning model
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
//do stuff
}
return View(model);
}
Without returning model
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
//do stuff
}
return View();
}
Usually you want the user to show an error message if the data he submitted is not valid (e.g. he did not enter a valid email address into a field that requries to be an email - see MVC ModelValidation for more information).
You use the ModelState.IsValid to check for that. In this case you usually show him the page he came from ("Register") and you also want to show the data he entered into the form fields (= RegisterModel). But you want to display an errormessage that tells him what fields are not correct.
If the user's data is correct and your action succeeds (in this case he was registered successfully) you usually do not show him the registration form again, but you would redirect him to a success page.
Here is a simple example how to validate, show errors and redirect after successfull action.
Example from your code:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
//do stuff
// redirect to a success page
return RedirectToAction("Success");
}
// data is not valid - show the user his data and error messages
// using Html Helper methods (see link for details)
return View(model);
}
On the Register view (Ifno - if you have a strongly typed view, you can use the HTML Helper overloads for that - e.g. use Html.LabelFor, TextboxFor etc methods):
Show general error message/summary;
...
<%= Html.ValidationSummary("Register was not successfull") %>
Show error message next to the inputs:
...
<%= Html.TextBox("Email") %>
<%= Html.ValidationMessage("Email", "*") %>
Will you view render without model passed to it? Probably not, so the second one will fail.
I would suggest you read about Post Redirect Get pattern
http://en.wikipedia.org/wiki/Post/Redirect/Get
The first action at the end is passing the Model to the view and the second one your returning back an empty view. So I would suggest you go for the first one
But when validation fails you should do the error handling this way
if (ModelState.IsValid)
{
//do stuff
}
else
{
ModelState.AddModelError("RegisterModel Errors", "some error occured");
}
return View(model);
Since you have a strongly typed view, in either case you will need to pass the corresponding model to the view (else your view may crash on trying to access properties on a null model). On success you can redirect to another page or you should be able to give user a notification, in the same page itself updating whether the operation is a success or fail (depends on whether you want a usual HTML based solution or an AJAX enabled solution). As for validation there are the options of usual client side validation and the jQuery based unobtrusive client side validation.
Here are couple of useful links
ASP.NET Model validation (this is MVC2 based but should be same for MVC3)
MVC3 unobtrusive client validation

Passing object from one action method to another in ASP.NET MVC 3

I am using ASP.NET and MVC 3 in visual studio and have a question about passing an object from one action method(called Search) to another(called SearchResult). I tried using ViewData but it didnt persist down to the View of SearchResult. Below is a snippet of my code, from within a single controller. 'Search' gets called when data has been collected from a form and submit has been called(hence the [HttpPost] declaration):
[HttpPost]
public ActionResult Search(Search_q Q){
// do some work here, come up with an object of type 'Search_a'
// called 'search_answer'.
ViewData["search_answer"] = search_answer;
return RedirectToAction("SearchResults");
}
public ActionResult SearchResult(Search_a answer)
{
return View(answer);
}
I also tried using RedirectToAction("SearchResults", new {answer = search_answer}); instead of the above call to RedirectToAction but my 'search_answer' still didnt persist to the View. What is the best way to send this Search_a object to the SearchResult View?
You can use TempData to pass the object.
[HttpPost]
public ActionResult Search(Search_q Q){
// do some work here, come up with an object of type 'Search_a'
// called 'search_answer'.
TempData["search_answer"] = search_answer;
return RedirectToAction("SearchResult");
}
public ActionResult SearchResult()
{
var answer = (Search_a)TempData["search_answer"];
return View(answer);
}
If TempData does not suffice (what Eranga suggested), because SearchResult is not somewhat dependent on a Redirect (though you can have checks to get around it), you might want to look at the Request object. You can likely store the data as one of the query parameters via Request.Params. This can take advantage of the ModelBinding filter chain that Asp MVC has.

Categories

Resources