Tuesday, April 23, 2013

The PRG /POST-REDIRECT-GET/ Pattern using ASP.NET MVC

This pattern is used to solve the double submit problem. When a user tries to refresh the result page of a post request, The page is resubmitted again resulting in undesirable results like double withdrawal of account, multiple orders etc.

If a post request is supposed to return a page, instead it should  does its side effect operation(e.g. saving order) and  redirect to a get request that returns the page. Thus result of the get request could be bookmarked and can be requested as needed with out a side effect(undesired additional orders).


The double submit problem is explained in depth in this article by Michael Jouravlev.

Using the ASP.Net MVC framework it is simple to implement the PRG pattern, below you will find a small 


code snipnet that uses the RPG pattern.


Step1(POST)  Controller action will make a redirect to Step 1(GET request) on error or if successful it will make a GET request to the next step 2(GET). Step 1(POST)  doesn't build and return pages it self.
[HttpGet]
[ImportModelStateFromTempData]
public ActionResult Step1(int id)
{

var m = _orderService.GetOrder(id);
return View(m);
}

[HttpPost]
[ExportModelStateToTempData]
public ActionResult Step1(Order m)

//If the model is valid(satisfies all the validation requirements set for it)
//persist it and make a get request to the next step 
//else make a redirect to GET request page 

if (ModelState.IsValid)
{
// save
-orderService.Save(m);
// Go to the next step (Step 2 here is a HttpGet ActionResult)
return RedirectToAction("Step2", new { id = m.OrderId });
}
//redirect to the Get Request

return RedirectToAction("Step1",new {id =m.OrderId});

}

[HttpGet]
[ImportModelStateFromTempData]
public ActionResult Step2(int id)
{

var m = _orderService.GetOrder(id);
return View(m);
}