ASP.NET MVC Tip #6 – Call RedirectToAction after Submitting a Form

In this tip, I explain why you should call the RedirectToAction() method after submitting form data instead of returning a view.

Imagine that you are collecting information from your website users with an HTML form. The HTML form is displayed by a controller action named HomeController.Create() and the form data is submitted to a controller action named HomeController.New() that adds the form data to the database. After the form data is submitted, you want to display the accumulated survey results (see Figure 1).

Figure 1 – Results.aspx View

image

There are two approaches that you might take to writing the New() controller action. In Listing 1, the New() action first submits the form data to the database (using LINQ to SQL) and then calls RedirectToAction() to redirect the user to the Results() action. In Listing 2, the New() action does not call RedirectToAction(). Instead, the Results.aspx view is returned directly by the New() action.

Listing 1 – SurveyController.vb

Public Class SurveyController
    Inherits System.Web.Mvc.Controller

    Private _db As New SurveyDataContext()

    Function Create()
        Return View()
    End Function

    Function [New](ByVal favoriteColor As String)

        ' Add new survey results to database
        Dim newSurvey As New Survey()
        newSurvey.FavoriteColor = favoriteColor
        newSurvey.EntryDate = DateTime.Now
        _db.Surveys.InsertOnSubmit(newSurvey)
        _db.SubmitChanges()

        ' Redirect to Confirm action
        Return RedirectToAction("Results")
    End Function

    Function Results()
        Return View(_db.Surveys)
    End Function

End Class

Listing 2 – Survey2Controller.vb

Public Class Survey2Controller
    Inherits System.Web.Mvc.Controller

    Private _db As New SurveyDataContext()

    Function Create()
        Return View()
    End Function

    Function [New](ByVal favoriteColor As String)

        ' Add new survey results to database
        Dim newSurvey As New Survey()
        newSurvey.FavoriteColor = favoriteColor
        newSurvey.EntryDate = DateTime.Now
        _db.Surveys.InsertOnSubmit(newSurvey)
        _db.SubmitChanges()

        ' Return Results view
        Return View("Results", _db.Surveys)
    End Function

End Class

So, there are two different approaches to showing a results page after submitting form data. You can either return RedirectToAction() or you can return View(). Which approach is better?

When you call RedirectToAction(), the ASP.NET MVC framework causes the web browser to make a new request to your website. The RedirectToAction() method returns a 302 – Object Moved status to the browser. This browser fetches the Results view.

So you might think calling RedirectToAction() is the poorer strategy. The browser has to do more work when you call RedirectToAction(). Something might go wrong on the network while the browser makes a new request. Using RedirectToAction() opens up more possibilities of things going wrong.

However, there are three good reasons to prefer RedirectToAction() over returning a view directly: two reasons are practical and one reason is philosophical. Let’s start with the practical reasons. If you don’t do a redirect, and the user hits the refresh/reload button in the browser, the database data is submitted more than once. In other words, if you don’t do a redirect, you can get duplicate database data in your database tables.

Now, it is true that modern browsers warn the user of this danger. Microsoft Internet Explorer 7.0 provides the nicely worded warning in Figure 2. So, perhaps this danger isn’t quite as bad as it was in the past.

Figure 2 – IE warning when refreshing after form post

image

The second practical reason is related to the first. If you bookmark the results page (or email a link to the page to a friend) and use the bookmark to open the page later, the database operation will happen without warning. The form will be submitted without data, client-side validation will be bypassed, and you will get the ugly page in Figure 2:

Figure 2 – Returning to Results bookmark

image

The third reason to prefer RedirectToAction() over View() is philosophical. The ASP.NET MVC framework provides a “RESTful” interface to your application. Different URLs correspond to different actions. If you return the Results view when the New() action is invoked, the correspondence between actions and views is broken. In other words, in a RESTful application, the view that you see should correspond to the URL that you see in your browser’s address bar.

If you call RedirectToAction() after submitting the form data, you’ll see Survey/Results in your browser’s address bar. If you call View() after submitting the form data, you’ll see Survey/New in your browser’s address bar. Because you are viewing the Results page, the first scenario makes more sense. The browser address bar should reflect the state of the web application. Doing a redirect enables you to keep the browser and server in sync.

If you would like to experiment with the two methods of submitting form data discussed in this tip, click the following link to download the code.

Download the Code

********* UPDATE ****

One nice thing about working at Microsoft is that you are surrounded by really smart people. After posting this blog entry, I ran into Brad Wilson (of xUnit fame) and he told me that there is a pattern that applies to the topic of this tip. The pattern is called the PRG pattern (Post-Redirect-Get pattern). Here’s the link to the Wikipedia entry:

http://en.wikipedia.org/wiki/Post/Redirect/Get

So, this tip should really be renamed to “Use the PRG Pattern when Submitting a Form”.

Discussion

  1. http:// says:

    What is the point of mvc for asp.net. Doesn’t seem to meet the whole Mort proposition of making developing easier.

  2. http:// says:

    @Dave — There are some heavy assumptions built into that question that I won’t touch :)

    The point of ASP.NET MVC is to provide a version of the ASP.NET framework that meets the needs of developers who want to build more testable applications and who want more control over the HTML rendered by their application. ASP.NET MVC will always be an alternative to ASP.NET Web Forms. Some developers will like MVC and some developers will like Web Forms.

  3. http:// says:

    Is it possible to pass a parameter, say “id”, to a controller action with redirectToaction in vb.net?

  4. rodrijp says:

    RedirectToAction has a parameter value to pass Id. new {id = “1″}

  5. Mose says:

    Stephen,

    the problem using RedirectToAction is that you cannot use the validation message of ModelState… that means all the current validation mechanisms (AddModelError) are useless…

  6. Jon says:

    IMHO:
    The AddModelError mechanisms still work as you don’t do a RedirectToAction on an error you would do a return View()

    Having said that I’m not sure how you get it to display a message to say that your changes were saved on the RedirectToAction()

  7. Fabio says:

    RedirectToAction would be great if it allowed us to persist ViewData or stuff through actions. Although I understand the reason for this behavior, it’s kinda complicated to use PRG pattern with ASP.NET MVC. If there was a mechanism to keep state among actions, then it would be really useful (and possible, I’d say).

  8. Hi..
    thanks for donwload code link..
    i get it.

  9. thanks for the code….

  10. reamon says:

    Regarding the “Different URLs correspond to different actions.” For ASP.NET MVC that’s accurate in that the URL will (usually) map to a single controller action method.

    But in the REST sense, it’s not an accurate view. In REST, URLs correspond to resources. On a specific resource, multiple verbs can be executed.

    With HTTP the verbs are get, post, put, etc. Those verbs can each be used against a single URL, and ASP.NET MVC can map to overloaded action methods. For instance, the Nerd Dinner example in C# uses multiple Create actions (same URL, 2 different action methods) to support the get and post verbs using the AcceptVerbs attribute.

    That brings us to an concern posted by Mose: “the problem using RedirectToAction is that you cannot use the validation message of ModelState…”

    To which Jon replied: “The AddModelError mechanisms still work as you don’t do a RedirectToAction on an error you would do a return View()”

    A response to a post should always be a redirect, even when validation fails. There is a bit more work to preserve the validation information (and the user’s inputs) across the redirect, but it can be done fairly easily.

    There is an approach provided in item 13 at: weblogs.asp.net/…/…-best-practices-part-1.aspx

    Also listed there are links to other approaches (including a link to this blog entry).

    As Walther points out “The browser address bar should reflect the state of the web application.” This means the response to a post should *always* be a redirect to a get, even when form validation errors occur. Posts change state. Gets show current state. A browser should always be showing the result of a get, never a post.

  11. Great Tips! Really these tips are very useful for me because i am doing some projects in .net so these tips will help me a lot. Thanks Stephen.

  12. will says:

    very helpful

  13. v243 I tried to mock a call to a Linq to SQL query, but I am struggling.

  14. ME degree says:

    Great Tips! Really these tips are very useful for me because i am doing some projects in .net so these tips will help me a lot. Thanks Stephen.

  15. i am doing some projects in .net so these tips will help me a lot. Thanks Stephen.

  16. hese tips will help me a lot. Thanks Stephen.

  17. Linq to SQL query, but I am struggling.

  18. V i am doing some projects in .net so these tips will help me a lot. Thanks Stephen.

  19. these tips will help me a lot. Thanks Stephen.

  20. tips will help me a lot. Thanks Stephen.

  21. Linq to SQL query, but I am struggling.

  22. tips will help me a lot. Thanks Stephen.

  23. I must admit that information in this post really interesting and useful.

  24. RedirectToAction would be great if it allowed us to persist ViewData or stuff through actions. Some developers will like MVC and some developers will like Web Forms.

  25. hn It looks like DataContextExtensions.cs line 45 of the Save method should pass the primaryKeyName through to Update.

  26. I must admit that information in this post really interesting and useful.

  27. Ronald Pettigrew says:

    Some developers will like MVC and some developers will like Web Forms. Excellent post, but it’s strange…

    online phd
    online colleges
    online degrees

  28. besthdsoft2 says:

    Blu-ray Ripper Step-by-step guide to rip Blu-ray to AVI, MPEG, WMV, MP4, Xvid, etc

    blu ray to wmv, blu ray dvd to mpeg converter, blu ray dvd to psp converter.

  29. zheng says:

    Ugg boots, uggs. Only the genuine UGG Australia brand are actually UGGs.
    UGG Boots
    UGG Boots sale
    UGG sale
    handbags
    100% Australia UGG Boots are under low price,Sheepskin Boots sale cheap discounted Uggs Sheepskin Boots are provided in our Uggs Women boots store
    Buy UGG Boots
    UGG
    UGGs
    Handbags Shop
    best ugg boots sale store,The ugg boots made form top qulity merino sheepskin.Our cheap ugg boots are comfortable enough to wear all day.

  30. HD Video Converter says:

    As the users of HD Camcorders like Sony, Canon, Panasonic, this HD Video Converter is necessary to help us convert hd Video easily and quickly. The Converter for HD provides several practical editing functions to help you achieve ideal output effect. Trim function is to cut videos into clips which you can just convert and transfer to your player. Crop function helps you remove black bars around the movie. You could use Effect function to adjust video brightness, contrast, saturation and more parameters. More powerful and considerate functions are waiting for you to explore.
    M2TS Converter and MTS Converter l MOD Converter