Post/Redirect/Get with new ASP.NET 5 & MVC 6

Post/Redirect/Get or PRG in short is a common pattern used amongst many web applications, that was designed to prevent duplicate submissions of the forms. Not using such pattern may result e.g. in multiple transactions by POSTing the same form twice, which is something that we definitely do not want to see in our applications. Although, it’s quite easy to be implemented in it’s purest form, it’s a little bit more tricky if we want to save the input data provided by the user (let’s say the form has a lot of fields, and regular redirect would reset it to its initial state since it renders a brand new view). In this post, I’ll present how to add such filters to the MVC application that will both save the input data and also the display the validation errors from the ModelState object.


 

At first, let’s start with the way it was being used in the previous versions of the ASP.NET MVC. This is really quite old solution (which has over 7 years now), but works well. It is described here at #13 Use PRG Pattern for Data Modification, so let me just copy & paste the source code:

And then you can decorate the controller actions with these filters:

I thought it will be pretty much the same in the new version of ASP.NET 5 and MVC 6, yet seems that I was wrong. I’m working on the web panel for the Warden project, and since I’ve decided it will be a cross-platform tool, it was quite natural to make use of the new ASP.NET 5.
So let me show you, step by step, how to achieve the same functionality as in the example above:

  • Install the Microsoft.AspNet.Session and Newtonsoft.Json NuGet packages.
  • In the Startup class add the following: services.AddSession() inside the ConfigureServices() and app.UseSession() within the Configure() method.
  • Great, now we can make use of the TempData, but beware it’s just the beginning.

Proceed by creating two extension methods for the JSON serialization – you don’t need to do this, but it cleans up the overall code a little bit:

Finally, let’s move on to the implementation of these filters. I’ll paste the code first and then describe what’s going on:

Even though it does the same thing, that stuff got more complicated while compared to the previous version. At first, you may notice that I’m using JSON to serialize the object stored in the TempData (which works with the session under the hood).
I’ve tried to serialize the whole ModelState in order to be able to invoke the Merge() method in the ImportModelStateFromTempData but without luck – some classes do not have the default constructors, therefore, I had to create the Entry class.
Eventually, you can see the loop that goes through all of the properties and sets the values and errors (if there are any).

And that’s all – it does work the same way as the previous implementation.
Feel free to tweak this code as I’m still getting to know the new ASP.NET 5 so I guess that some things could’ve been done better.
Anyway, I’ve achieved the goal and have managed to get the PRG pattern working in an old fashioned way while using the newest version of the framework.

4 Comments Post/Redirect/Get with new ASP.NET 5 & MVC 6

  1. Kukkimonsuta

    You do not violate principles of Post/Redirect/Get pattern when you return view directly on post if there were validation errors since the validation will fail again and the result will be the same while nothing (besides audit logs maybe, which is ok) will be written again if user hits refresh.

    This forces you to use sessions (you should do your best to avoid those and keep your app stateless) and TempData – which sounds like awesome thing to have, but in reality it’s something that will eventually bite you (multi tab scenarios, refreshing the page in wrong moment..).

    +1 for effort, but seriously – return view on post if there were validation errors and redirect only when the action was successful.

    Reply
    1. Piotr Gankiewicz

      Good point about the principles violation and as for the sessions you’re absolutely right that its usage should be kept to a bare minimum (or none at all).

      The main idea of this post, however, was to show how the old implementation of this pattern can be rewritten to the new version of the framework. I do agree that it would be wise to not use TempData at all and make sure that the client side e.g. cache the input data, yet it was not really the point here.

      Reply
    1. Piotr Gankiewicz

      Hi,
      Haven’t tried it out yet, but if you try to use the same code, you will notice that filterContext now has the Controller property. You could try to cast it e.g. to the Controller class and if it’s not null, you should be able to access the TempData via this controller. I’m not sure it will work, but you can give it a go.

      Reply

Leave A Comment

Your email address will not be published. Required fields are marked *