本文地址http://www.cnblogs.com/outtamyhead/archive/2013/03/29/2988632.html,轉載請保留本地址
說在前面:
1、由於是頭次翻譯整本書籍,所以錯誤難免,希望大家都提出來,翻譯的不好還望大家少拍磚多鼓勵。
2、該系列沒有按照原文直譯,而是加入了我的一些言語在里面(在沒有改變原意的情況下),所以大家在看的時候希望有所對照。
3、該系列每周出一或二篇博客,因為我最近很忙,一直在加班,很累的說。
4、該系列不提供原版文字,希望看原版的可以自行下載Pdf。
5、該系列省去了前面的廢話,單刀直入,講主體內容。
第二章:第一個ASP.NET MVC4程序(下二)
處理表單
當表單被傳到服務器之后,我們並沒有告訴MVC我們想做什么。從目前來看,點擊【Submit RSVP】按鈕只是清除了我們在表單里留下的內容。這是因為表單回遞到Home控制器的RsvpForm動作方法后,只是告訴了MVC要重新渲染這個視圖。
提示:你也許會好奇為什么當視圖重新渲染之后輸入的數據會丟失。假如是這樣的話,你大概會開發一個ASP.NET Web Froms,在上面這種情況下它會自動保存數據。我們會在一會告訴你如何達到這同樣的效果。
為了接收和處理提交的表單數據,我們打算做一件聰明的事情。為了創建下面的內容,我們會添加第二個RsvpForm動作方法。
一個響應HTTP GET請求的方法:GET請求就是某人點擊一個鏈接瀏覽器發出的請求。這樣的動作會使你在初次訪問/Home/RsvpForm時顯示一個初始空白的表單。
一個響應HTTP POST請求的方法:默認情況下,通過Html.BeginForm()渲染的表單會被瀏覽器以POST請求的方式提交。這種動作將負責接收提交的數據,並決定它該怎么做。
在不同的C#方法中處理GET和POST請求,會使我們的代碼保持整潔,因為這兩種方法有不同的職責。這兩個動作方法都有相同的URL調用,但是MVC會確保調用到合適的方法,基於我們正在處理的一個GET或POST請求。清單2-14列出了我們在HomeController添加的內容
清單:2-14 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using PartyInvites.Models; namespace PartyInvites.Controllers { public class HomeController : Controller { public ViewResult Index() { int hour = DateTime.Now.Hour; ViewBag.Greeting = hour < 12 ? "Good Morning" : "Good Afternoon"; return View(); } [HttpGet] public ViewResult RsvpForm() { return View(); } [HttpPost] public ViewResult RsvpForm(GuestResponse guestResponse) { // TODO: Email response to the party organizer return View("Thanks", guestResponse); } } }
我們在已經存在的RsvpForm動作方法上添加了HttpGet特性。這就告訴MVC這個方法只有在GET請求時被用到。我們再添加一個RsvpForm的重載方法,這個方法需要一個GuestResponse參數並加上HttpPost特性。這個特性會告訴MVC這個新方法將會處理POST請求。注意我們也引入了PartyInvites.Models命名空間--這樣我們就可以直接使用GuestResponse模型類型而不需要限定類名。我們會在后面解釋我們添加的這些是如何工作的。
使用模型綁定
第一個RsvpForm動作方法的重載方法會像以前那樣渲染相同的視圖。它產生的表單如圖2-16所示。第二個重載方法比較有趣,因為有參數,但是在響應HTTP POST請求時會給這個動作方法賦值,而這個GuestResponse類型是一個C#類,這兩者如何聯系呢?
答案就是模型綁定,這是在解析輸入數據以及用鍵/值對來發布主域模型類型的屬性等方面的一個非常有用的MVC特性。在使用HTML輔助方法時這個過程卻是相反的;那就是,當創建表單的數據發送到客戶端,我們生成HTML input元素,它的id和name特性的值對應模型類屬性名稱。相比之下,使用模型綁定,input元素的名稱通常會被設置為模型類中一個實例的屬性的值,隨后傳遞給我們能夠使用POST的動作方法。
模型綁定是一種強大的並且可自定義的功能,利用HTTP請求直接消除了研磨和辛勞的處理。讓我們通過C#對象去工作而不是通過Request.Form[]和Request.QueryString[]值。作為參數傳遞到我們動作方法中的GuestResponse對象自動發布了表單字段的數據。在第22章,我們將深入的了解包括模型綁定以及它的自定義的細節。
渲染其他視圖
第二個RsvpForm動作方法的重載方法也說明了我們如何告訴MVC在響應請求時去渲染一個特定的視圖,而不是默認的視圖。這是相關的代碼段:
return View("Thanks", guestResponse);
這個調用的View方法告訴MVC去找到並且渲染一個叫做Thanks的視圖然后把GuestResponse對象傳遞到視圖上。要創建我們指定的視圖,就在HomeController的一個方法里右鍵選擇【Add View】。把視圖名字設置為Thanks。如圖2-17
我們打算創建另外一個強類型的視圖,所以在【Add View】對話框中選中那一項。我們為視圖選擇的數據類必須與我們通過View方法傳遞到視圖上的類相一致,所以要確保GuestResponse被選中。確保【Use a layout or master page】項未被選中,【View engine】設置為Razor,【Scaffod template】設置為Empty。
點擊【Add】按鈕來創建新視圖。因為這個視圖和Home控制器有關,所以MVC創建的這個視圖的位置是~/Views/Home/Thanks.cshtml。編輯這個視圖使它和清單2-15一樣--我們高亮顯示了你需要添加的代碼。
清單2-15 @model PartyInvites.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Thanks</title> </head> <body> <div> <h1>Thank you, @Model.Name!</h1> @if (Model.WillAttend == true) { @:It's great that you're coming. The drinks are already in the fridge! } else { @:Sorry to hear that you can't make it, but thanks for letting us know. } </div> </body> </html>
Thanks視圖基於我們在RsvpForm動作方法中通過View方法傳遞的GuestResponse的屬性值來展現內容。@model運算符指定主域模型類型。要訪問主域對象中一個屬性的值,我們要使用Model.PropertyName。例如,要獲得Name屬性的值,我們就調用Model.Name。不用擔心如果Razor語法沒有表達出它的含義--我們會在第5章詳細解釋。
現在我們已經創建了Thanks視圖,我們有了一個通過MVC處理表單的基本的工作示例。
運行程序,點擊【RSVP Now】鏈接,在表單中添加一些數據,然后點擊【Submit RSVP】按鈕。你會看到如圖2-18所示的結果(如果你輸入的名字不是Joe或者你說你不能參加,這會有些不同)。
添加驗證
我們現在要給我們的應用程序添加驗證。如果我們不做這步操作,我們的用戶會輸入一些沒有意義的數據或者甚至提交一個空表單。
在一個MVC應用程序中,在主域模型上添加驗證是很典型的一種方式,而不是在用戶端。這就意味着在一個地方定義我們驗證標准,它就會在用到的模型類的任何地方發揮作用。ASP.NET MVC 支持從System.ComponentModel.DataAnnotations命名空間聲明的屬性定義的驗證規則。清單2-16說明了這些特性如何添加到GuestResponse模型類。
清單2-16 using System.ComponentModel.DataAnnotations; namespace PartyInvites.Models { public class GuestResponse { [Required(ErrorMessage = "Please enter your name")] public string Name { get; set; } [Required(ErrorMessage = "Please enter your email address")] [RegularExpression(".+\\@.+\\..+", ErrorMessage = "Please enter a valid email address")] public string Email { get; set; } [Required(ErrorMessage = "Please enter your phone number")] public string Phone { get; set; } [Required(ErrorMessage = "Please specify whether you'll attend")] public bool? WillAttend { get; set; } } }
驗證規則用粗體顯示了。MVC會自動檢測這些特性並在模型綁定過程中驗證數據。注意我們導入了包含驗證的命名空間,因此我們可以直接使用它們而不需要限定它們的名字。
提示:如前所述,我們為WillAttend屬性添加了一個可為空的布爾類型。因此我們可以添加Required驗證特性。如果我們使用正規的布爾類型,我們通過模型綁定收到的值就只有true和false,並且我們不能知道用戶是否選擇了值。一個可為空的布爾包括三個可能值:true、false和null。如果用戶沒有選擇一個值,null就會被用到,這就引起了Required特性去產生一個錯誤驗證。
我們可以通過在控制器類中的ModelState.IsValid屬性來檢查如果有驗證問題。清單2-17展示了在POST方式的RsvpForm動作方法如何做這件事。
清單2-17 ... [HttpPost] public ViewResult RsvpForm(GuestResponse guestResponse) { if (ModelState.IsValid) { // TODO: Email response to the party organizer return View("Thanks", guestResponse); } else { // there is a validation error return View(); } } …
如果沒有驗證錯誤,我們就告訴MVC去渲染Thanks視圖。如果存在驗證錯誤,我們重新渲染RsvpForm視圖通過不帶參數的View方法。
當出現錯誤時只顯示表單是沒有用的--我們需要給用戶提供一些問題的描述和我們為什么不能接受提交的表單數據。我們在RsvpForm視圖中通過Html.ValidationSummary輔助方法來實現這一點,如清單2-18所示
清單2-18 @model PartyInvites.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RsvpForm</title> </head> <body> @using (Html.BeginForm()) { @Html.ValidationSummary() <p>Your name: @Html.TextBoxFor(x => x.Name) </p> <p>Your email: @Html.TextBoxFor(x => x.Email)</p> <p>Your phone: @Html.TextBoxFor(x => x.Phone)</p> <p> Will you attend? @Html.DropDownListFor(x => x.WillAttend, new[] { new SelectListItem() {Text = "Yes, I'll be there", Value = bool.TrueString}, new SelectListItem() {Text = "No, I can't come", Value = bool.FalseString} }, "Choose an option") </p> <input type="submit" value="Submit RSVP" /> } </body> </html>
如果沒有錯誤,Html.ValidationSummary方法會在表單中創建一個隱式列表項占位符。MVC使占位符可見並添加錯誤信息通過驗證特性。在圖2-19中說明了它是怎么出現的。
Thanks視圖不會在用戶面前展現直到我們添加在GuestResponse類上的驗證限制得到滿足。需要注意的是當視圖通過驗證集合重新渲染的時候我們添加到表單的數據是被保存的並被再次展現在視圖上。這是模型綁定的另一個優勢。
提示:如果你用ASP.NET Web Forms工作,你會了解Web表單有一個“服務端控件”概念,它的持久狀態是通過把序列化的值保存到一個叫做_VIEWSTATE的隱藏的表單字段實現的。ASP.NET MVC模型綁定不同於服務端控件概念的Web表單,回遞,或視圖狀態。ASP.NET MVC不會往你渲染的HTML頁注入_VIEWSTATE隱藏字段。