• Full stack dev • Part of the .Net Foundation org •
Published Sep 19, 2015
I have seen some strange things going on in MVC controllers, but one thing that really grinds my gears is the following code:
public ActionMethod CreateUser()
{
// Do some stuff
return View();
}
[HttpPost]
public ActionMethod SaveUser(ViewModel model)
{
if(ModelState.IsValid) { // Save to db }
return View(model);
}
Where do I start, there are a few:
Why do we need two different ActionMethod
names? CreateUser and SaveUser?
You can simply have a Create()
HttpGet
and a Create(ViewModel model)
HttpPost
. It is easier to read and actually makes sense.
The user can easily resubmit the POST
by pressing F5
.
This could potentially be very bad for the user, for example, an online payment system, if this type of implementation was in place and the user pressed F5
, and it would re-submit the form and take the payment again.
You could even be adding an item to some sort of shopping basket, pressing F5
will keep adding the same item over and over.
We can easily fix this common issue by using the Post Redirect Get (PRG) pattern.
public ActionMethod CreateUser()
{
// Do some stuff
return View();
}
[HttpPost]
public ActionMethod CreateUser(ViewModel model)
{
if(ModelState.IsValid)
{
// Save to db
return RedirectToAction("CreateUser");
}
return View(model);
}
It’s that simple.
Make the ActionMethods
have the same name (They need different method signatures) and decorate the POST
action with [HttpPost]
, this means this ActionMethod
can only be used with an HTTP POST
request.
After all the processing is done e.g. Save user to the DB all we need to do is return the Get ActionMethod
in my example, this is the CreateUser()
method. So now if the user presses F5
it will simply issue a new request to the GET
CreateUser()
method and not resubmit the POST
.