POST-Redirect-GET Pattern

HTTP supports several methods that define the nature of the current request. The two most important ones are GET and POST. GET is the primary method to get content (so called entities) from the server such as HTML pages, images, CSS style sheets etc. The POST method on the other hand is meant to transport entities to the server, for example login credentials or a blog comment. On the server side a POST request often results in an update of certain data (databases, session state).

Both GET and POST can return an entity as a response. For GET this is obvious – it’s what the method exists for in the first place. For POST it might sound reasonable in the first place as well, but it brings a pile of problems.

A simple scenario

Imagine you fill in a sign-up form of some web based e-mail service and POST it to the server using a submit button. The server processes the new account and updates its database. Maybe it even logs you in directly. In response of the POST request the server directly shows you a view of your inbox. Here’s a diagram of what happens between browser and server:


  • The browser POSTs form data to an URL called signup.aspx
  • The server processes the request
  • The server responds with a status code of 200 (OK) and sends back a view of the new users inbox rendered as HTML

You leave the computer to have a coffee and when you come back 5 minutes later you refresh the page (using CTRL+R or F5 or whatever shortcut your browser uses) to see whether you already have new messages. You are a bit puzzled why this (or a similar) message box appears:


You click on OK and are even more confused as the page that appears says “This user name is already taken” instead of showing your inbox .

What has happened? Remember that the page you saw was the response of a POST request (submitting the sign up form). When you refreshed the page and confirmed to “resend the data” you actually repeated the POST request with the same form data. The server processed the “new” account and found that the user name is already in use (by yourself!), therefore it showed an error. “But wait”, you say, “I just wanted the server to refresh the view of my inbox, what have I done wrong? ” The answer is: nothing! The problem is that the application abused the POST response to transport an entity back to the client that should have been accessed with a GET request in the first place.

POST related issues

Here are some of the problems that occur if you abuse POST requests to return entities:

1. Refreshing the page results in a re-transmission of the POST data

This is what I described above. Hitting “refresh page” for a reponse based on a POST request will re-issue the POST request. Instead of refreshing what you see this will repeat what you did to reach the current page. This is not “refresh page” anymore, it becomes “repeat last action” – which is most likely not what the user wants. If you see a summary page after you have submitted an order in an online store, you don’t want F5 to drop another order, do you?

2. POST responses are hard to bookmark

Bookmarks (or favourites etc.) normally only remember the URL of the bookmarked page (along with some user supplied meta data). Because a POST request transports data in the request body instead as query parameters in the URL like GET does, bookmarking the result of a POST will not work in most cases.

3. POST responses pollute the browser history

If the browser keeps the result of a POST request in it’s history, going back to that history entry will normally result in POST data to be retransmitted. This again causes the same issues as mentioned in point 1.


“But I need POSTs to send forms to the server – how can I avoid the problems mentioned above?” you might say. Here’s where the POST-Redirect-GET (PRG hereafter) pattern enters the stage.

Instead of sending entity content with the POST response after we processed the request, we return the URL of a new location which the browser should visit afterwards. Normally this new location shows the result of the POST or an updated view of some domain model.

This can be achieved by not returning a result code of 200 (success) but instead returning a status code that indicates a new location for the result, for example 303 (“See other”) or 302(“Found”/”Moved temporarily”), the latter of which is used most often nowadays. Together with the 30x result code a Location header is sent which contains the URL of the page to which the request is redirected. Only the headers are sent, no body is included.

If the browser sees the 30x status code, it will look for the Location header and issue a GET request to the URL mentioned there. Finally the user will see the body of that GET request in the browser.

The browser-server communication would look like this:


  • The browser POSTs to signup.aspx
  • The server updates some state etc.
  • The response is 302 redirect with a Location header value of inbox.aspx
  • The browser realizes that the response is redirected and issues a GET to inbox.aspx
  • The server returns 200 together with the content of the resource.

What do we gain?

  • The page can be safely refreshed. Refreshing will cause another GET to inbox.aspx which won’t cause any updates on the server
  • The result page can be easily bookmarked. Because the current resource is defined by the URL a bookmark to this URL is likely to be valid.
  • The browser history stays clean. Responses that have a redirect status code (such as 302) will not be put into the browser cache by most browsers. Only the location to which the response is redirecting is. Therefore signup.aspx won’t be added to the history and we can safely go back and forth through the history without having to resubmit any POST data

The problem with ASP.NET WebForms
Now that you know about POST-Redirect-GET you are of course eager to use it (at least I hope I could convince you). But as an ASP.NET WebForms developer you will soon run into problems: ASP.NET WebForms is fundamentally based on POSTs to the server. In essence, all ASP.NET web pages are wrapped in one huge

element with “method” set to “POST”. Whenever you click a button, you essentially POST all form fields to the server. Of course you can redirect from a Button.Click handler. If you do so, you’re applying PRG. At the same time you’re working quite against the WebForms philosophy, especially the ViewState (which will get lost as soon as you redirect), which will force you to rethink a lot of your application logic. And if you don’t rely on all this postback behaviour inherent to ASP.NET WebForms you might as well ask why you’re using WebForms in the first place.
This makes clear why a lot of developers (including me) think that WebForms are inherently “broken” (viewstate, ubiquitous postbacks and the hard-to-mock HttpContext are just a few reasons). If you share these concerns but like .NET just as I do, you might want to look at alternate .NET based web frameworks such as Castle MonoRail or ASP.NET MVC.

See entire article:

Why does C# have both ‘ref’ and ‘out’?

Ref and out parameter passing modes are used to allow a method to alter variables passed in by the caller. The difference between ref and out is subtle but important. Each parameter passing mode is designed to apply to a slightly different programming scenario. The important difference between out and ref parameters is the definite assignment rules used by each.
The caller of a method which takes an out parameter is not required to assign to the variable passed as the out parameter prior to the call; however, the callee is required to assign to the out parameter before returning.
Here’s a simple example:

 class OutExample{
      // Splits a string containing a first and last name separated
      // by a space into two distinct strings, one containing the first name and one containing the last name

      static void SplitName(string fullName, out string firstName, out string lastName){
            // NOTE: firstName and lastName have not been assigned to yet.  Their values cannot be used.
            int spaceIndex = fullName.IndexOf(‘ ‘);
            firstName = fullName.Substring(0, spaceIndex).Trim();
            lastName = fullName.Substring(spaceIndex).Trim();

      static void Main(){
            string fullName = “Yuan Sha”;
            string firstName;
            string lastName;

            // NOTE: firstName and lastName have not been assigned yet.  Their values may not be used.
            SplitName(fullName, out firstName, out lastName);
            // NOTE: firstName and lastName have been assigned, because the out parameter passing mode guarantees it.
            System.Console.WriteLine(“First Name ‘{0}’. Last Name ‘{1}'”, firstName, lastName);

One way to think of out parameters is that they are like additional return values of a method. They are very convenient when a method returns more than one value, in this example firstName and lastName. Out parameters can be abused however. As a matter of good programming style if you find yourself writing a method with many out parameters then you should think about refactoring your code. One possible solution is to package all the return values into a single struct.
In contrast ref parameters are considered initially assigned by the callee. As such, the callee is not required to assign to the ref parameter before use. Ref parameters are passed both into and out of a method.
Here’s an example:

class RefExample{
      static object FindNext(object value, object[] data, ref int index){
            // NOTE: index can be used here because it is a ref parameter
            while (index < data.Length){
                  if (data[index].Equals(value)){
                        return data[index];
                   index += 1;
             return null;

      static void Main(){
            object[] data = new object[] {1,2,3,4,2,3,4,5,3};
            int index = 0;
            // NOTE: must assign to index before passing it as a ref parameter
            while (FindNext(3, data, ref index) != null){
                  // NOTE: that FindNext may have modified the value of index
                  System.Console.WriteLine(“Found at index {0}”, index);
                  index += 1;
            System.Console.WriteLine(“Done Find”);

The two parameter passing modes addressed by out and ref are subtly different, however they are both very common. The subtle difference between these modes leads to some very common programming errors. These include:

  • not assigning a value to an out parameter in all control flow paths
  • not assigning a value to variable which is used as a ref parameter

Because the C# language assigns different definite assignment rules to these different parameter passing modes, these common coding errors are caught by the compiler as being incorrect C# code.
The crux of the decision to include both ref and out parameter passing modes was that allowing the compiler to detect these common coding errors was worth the additional complexity of having both ref and out parameter passing modes in the language.