[翻译] ASP.NET MVC Tip #6 – 提交表单后如何进行重定向

原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/06/20/asp-net-mvc-tip-6-call-redirecttoaction-after-submitting-a-form.aspx

摘要:在这个Tip中,Stephen Walther介绍了当提交表单后如需重定向,为何需要调用RedirectToAction方法进行重定向,而不是直接返回一个视图。

假设你正在用一个HTML表单从用户那里收集信息。该HTML表单是由名为HomeController.Create()的控制器action显示的,而数据提交到名为HomeController.New()的控制器action,它会将表单中的数据添加到数据库中。在表单数据提交后,你希望显示聚合统计结果(如图1)。

图1 - Results.aspx视图


在编写New()控制器action时有两种方法。在清单1中,New() action首先将表单数据提交到数据库(使用LINQ to SQL),然后调用RedirectToAction()将用户重定向到Results() action。在清单2中,New() action没有调用RedirectToAction()。而是直接从New() action返回Results.aspx视图。

清单1 - SurveyController.vb

 1Public Class SurveyController
 2    Inherits System.Web.Mvc.Controller
 3 
 4    Private _db As New SurveyDataContext()
 5 
 6    Function Create()
 7        Return View()
 8    End Function

 9 
10    Function [New](ByVal favoriteColor As String)
11 
12        ' Add new survey results to database
13        Dim newSurvey As New Survey()
14        newSurvey.FavoriteColor = favoriteColor
15        newSurvey.EntryDate = DateTime.Now
16        _db.Surveys.InsertOnSubmit(newSurvey)
17        _db.SubmitChanges()
18 
19        ' Redirect to Confirm action
20        Return RedirectToAction("Results")
21    End Function

22 
23    Function Results()
24        Return View(_db.Surveys)
25    End Function

26 
27End Class

清单2 - Survey2Controller.vb

 1Public Class Survey2Controller
 2    Inherits System.Web.Mvc.Controller
 3 
 4    Private _db As New SurveyDataContext()
 5 
 6    Function Create()
 7        Return View()
 8    End Function

 9 
10    Function [New](ByVal favoriteColor As String)
11 
12        ' Add new survey results to database
13        Dim newSurvey As New Survey()
14        newSurvey.FavoriteColor = favoriteColor
15        newSurvey.EntryDate = DateTime.Now
16        _db.Surveys.InsertOnSubmit(newSurvey)
17        _db.SubmitChanges()
18 
19        ' Return Results view
20        Return View("Results", _db.Surveys)
21    End Function

22 
23End Class

因此,在提交表单数据后,有两种方式可以显示结果页。既可以返回RedirectToAction(),也可以返回View()。究竟哪种更好一些呢?

当你调用RedirectToAction()时,ASP.NET MVC框架会导致Web浏览器产生一个新的重定向。RedirectToAction()方法向浏览器返回一个302 - Object Moved状态。然后浏览器会获取Results视图。

因此你可能会认为调用RedirectToAction()是一种不好的方式。在调用RedirectToAction()时浏览器会做更多的工作。当浏览器发起新的请求时网络可能会出现错误。实用RedirectToAction()增加了出错的可能性。

然而,有三个很好的原因可以表明RedirectToAction()要优于直接返回一个视图。两个原因是实际的,还有一个哲学上的原因。我们来从实际的原因开始。如果没有做重定向,而用户单击了浏览器的刷新/重新加载按钮,数据库的数据会被提交多于一次。换句话说,如果没有进行重定向,数据库表中可能会出现重复的数据。

现在,很多流行的浏览器会在遇到这种危险情况时向用户发出警告。Microsoft Internet Explorer 7.0提供了如图2所示的警告。因此,相对于过去而言,这种危险情况可能还不是最坏的。

图2 - IE在表单提交后的刷新提出的警告


第二个实际原因与第一个相关。如果你将结果页放在书签/收藏夹中(或通过Email将结果页链接发给朋友),并在之后用书签打开页面,数据操作会在没有提示的情况下发生。这会提交一个没有数据的表单,客户端验证将被忽略,你会得到如图3所示的丑陋页面:

图3 - 使用书签回到结果页


RedirectToAction()优于View()的第三个原因是哲学上的。ASP.NET MVC框架为你的应用程序提供了一个“静态”的界面。不同的URL代表了不同的操作。如果你在New()动作中返回了Results视图,动作和视图之间的这种对应关系就被破坏了。换句话说,在一个“静态”的应用程序中,你看到的视图应该和你在浏览器地址栏中看到的URL地址是对应的。

如果你在提交表单数据后调用了RedirectToAction(),你会在浏览器地址栏中看到Survey/Results这样的地址。如果你在表单提交后调用的是View(),你在浏览器地址栏中看到的地址时Survey/New。由于你看到的是Results页,第一种情形更有意义。浏览器的地址栏应该反映Web应用程序的状态。进行重定向可以保持浏览器和服务器之间的同步。

******** (原著作者的)更新 *********

在Microsoft工作最好的事情就是你周围总是围绕着一群非常聪明的人。在发表了这篇Blog之后,我跑进(以xUnit著称的)Brad Wilson的屋里,他告诉我这个Tip的主题中应用了一个模式。这个模式被称作PRG模式(Post-Redirect-Get模式)。这里是该模式在Wikipedia中的入口:

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

因此,这篇Tip应该改名叫“在提交表单时使用PRG模式”。

此处下载源代码:http://weblogs.asp.net/blogs/stephenwalther/Downloads/Tip6/Tip6.zip

-----

广告:[.NET正则表达式库] http://regex-lib.net/

-----

声明:
原作者已撰写到Tip#18,对于进度的缓慢,老刘在这给您说声抱歉!另外,欢迎大家直接阅读原文。最后,骂人请登录。

posted @ 2008-07-12 09:24  Anders Liu  阅读(3033)  评论(0编辑  收藏  举报