原文地址: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 SurveyControllerClass SurveyController
2 Inherits System.Web.Mvc.Controller
3
4 Private _db As New SurveyDataContext()
5
6 Function Create()Function Create()
7 Return View()
8 End Function
9
10 Function [()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()Function Results()
24 Return View(_db.Surveys)
25 End Function
26
27End Class
清單2 - Survey2Controller.vb
1Public Class Survey2ControllerClass Survey2Controller
2 Inherits System.Web.Mvc.Controller
3
4 Private _db As New SurveyDataContext()
5
6 Function Create()Function Create()
7 Return View()
8 End Function
9
10 Function [()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。
-----
廣告:[.NETRegex庫] http://regex-lib.net/。
-----
聲明:
原作者已撰寫到Tip#18,對於進度的緩慢,老劉在這給您說聲抱歉!另外,歡迎大家直接閱讀原文。最後,罵人請登入。