Jamie

• Full stack dev • Part of the .Net Foundation org •

Home

MVC Post Redirect Get Pattern

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);
}


What’s the problem with this?

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.

The Solution

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.