This article requires a basic understanding of MVC architecture and design pattern concepts. If you are very new to MVC then I suggest you understand MVC architecture before continue this article.
Let's talk the PRG design pattern and it's uses. PRG stands for Post Redirect Get. Fine, but why? Let's implement one small MVC application and we will see the real problem and scenario where we can use the PRG design pattern.
The problem is very common, and I am sure in your programmer and user life, you have encountered this situation. Let's consider, we have one Web form to collect user's information, very simple and clean. The user has filled in the necessary fields and hit the submit button. It is obvious it will hit some action belonging to some controller (defined in the controller) to save data in the database (or somewhere).
We are assuming that we are a good programmer (Really? Let's see. Haha..) and the data has been submitted. Now the user has hit the refresh button. Oh suck, it has called the action again? Let's see it in reality.
My Simple Model
This is kept simple intentionally because our point of discussion is different.
namespace MVC.Models
{
public class person
{
public string _name{get;set;}
public string _surname { get; set; }
public int _age { get; set; }
}
}
Here is my view
Which is a strong type in nature and I am targeting the “SaveData” action for the “person” controller.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MVC.Models.person>" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title>person</title>
</head>
<body>
<div>
<% using (Html.BeginForm("SavePerson","person")){ %>
Name : <%= Html.TextBox("_name") %> <br />
Surname: <%= Html.TextBox("_surname") %> <br />
Age: <%= Html.TextBox("_age") %><br />
<input value="Register" type="submit" />
<% } %>
</div>
</body>
</html>
Now, let's see the controller implementation. In the person controller we have defined two actions, the AddNew() action will return this person view and the SavePerson() action will collect form data using a model binding technique.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVC.Models;
namespace MVC.Controllers
{
public class personController : Controller
{
public ActionResult AddNew()
{
return View("person");
}
public ActionResult SavePerson([Bind] person p)
{
return Content("Data Saved");
}
}
}
Now, if we hit the submit button as in the following:
Then we will see the following screen and we are seeing that the data has come as the action's parameter.
And we will get the result as in the following.
Now, let's hit the refresh button of the browser and let's see the result.
And if we press retry then it will hit the controller's action again.
Since it's hitting the same controller again, there might a great chance to save a duplicate record in the database that we don't want at all.
Then what is the solution? The PRG design pattern. How will it solve the problem? When we submit a form's data it makes a POST request to the server and we know that the POST method is harmful in the page reload operation.
So, the trick is that we will make a POST request to the server and the server will transfer the request into the GET request.
Then the result page will display by the GET request and when we make another browser refresh the next time, it will make a GET request to the server, which is not at all harmful.
Ok, we have learned the mechanism. Now let's implement it in an application. For that we need to make a small change in the controller.
namespace MVC.Controllers
{
public class personController : Controller
{
public ActionResult AddNew()
{
return View("person");
}
public ActionResult SavePerson([Bind] person p)
{
return RedirectToAction("PRG", "person");
}
public ActionResult PRG()
{
return Content("Data Saved");
}
}
}
We have added another action named “PRG” and from the SavePerson() action we are redirecting the context to the PRG() action using the “RedirectToAction()” method.
Now when we refresh again it will hit the “PRG()” action, not the “SavePerson()” action.
Conclusion
Though this type of redirection eats server resources, the business needs and security comes before performances. Happy day.