Post-Redirect-Get and TempData with ASP.NET Core

The Post-Redirect-Get (PRG) pattern prevents duplicate form submissions when the user refresh 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 clearly 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 to request 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 an 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 clearly a way to handle the Post/Redirect/Get scenario.

Here's some great resources:

Leave a reply