Post-Redirect-Get and TempData with ASP.NET Core
The Post-Redirect-Get (PRG) pattern prevents duplicate form submissions when the user refreshes the page. Here's the sequence diagram:
Sequence diagram without TempData
As you can see, the server query the database twice to display the page to the user. This is inefficient, but how can you improve this? The time between the two requests is very short (about 1 second). So, maybe you can store the object in memory, and reuse it when the user makes the second request.
The ASP.NET MVC framework provides a mechanism to store data between two requests: TempData
. When you use TempData
, the value is store in an encrypted cookie that is sent to the client. At the next request, the TempData
dictionary is restored from the cookie. This way you don't need to reload the data from the database to handle the second request. This is useful in a PRG pattern. Indeed, you may have already loaded the data in the POST request. So, TempData
will store the data between the POST and the GET requests. This avoid requesting the database to handle the GET request.
Sequence diagram with TempData
Let's see how to use TempData
!
First you must add the service in the Startup.cs
file:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Add the temp data provider
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
}
Let's create a very simple form:
@model User
<form asp-controller="Home" asp-action="Edit" method="post">
<input asp-for="Id" />
<input asp-for="DisplayName" />
<button type="submit">Submit</button>
</form>
Here's the controller:
[HttpGet]
public IActionResult Edit(int id)
{
User user = null;
var value = TempData["User"];
if(value is string json)
{
user = JsonConvert.DeserializeObject<User>(json);
}
if (user == null || user.Id != id)
{
user = _userRepository.Load(id);
}
return View(user);
}
[HttpPost]
public IActionResult Edit(User user)
{
_userRepository.Save(user);
TempData["User"] = JsonConvert.SerializeObject(user);
return RedirectToAction("Edit", new { id = user.Id });
}
You can only store string values in the TempData
dictionary. The quick workaround is to serialize your data in JSON or any other format. You can also store the id of the data and store the data elsewhere such as a static dictionary or a NoSQL database.
#Conclusion
TempData
can be used to store data between two consecutive requests. This is a way to handle the Post/Redirect/Get scenario.
Here are some great resources:
- Introduction to session and application state in ASP.NET Core
- CookieTempDataProvider.cs
- Storing objects (non-string things) in TempDataDictionary does not round trip correctly
Do you have a question or a suggestion about this post? Contact me!