天天看點

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

本節書摘來自異步社群《精通 asp.net mvc 4》一書中的第2章,第2.4節,作者: 【美】adam freeman ,譯者: 李萍 , 徐燕萍 , 林逸 , 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

精通 asp.net mvc 4

本章的其餘部分将通過建立一個簡單的資料錄入應用程式,來考察mvc的更多基本特性。本節将分步進行,目的是示範mvc的運轉,是以會跳過對幕後工作原理的一些解釋。不用擔心——在後面的章節中還會重新深入地讨論這些論題。

設想一個朋友要主辦一個“新年除夕晚會”,需要建立一個web網站,以便讓被邀請人進行rsvp(電子回複)。這個網站需要以下四個關鍵特性:

一個顯示此晚會資訊的首頁;

一個可以用來進行rsvp(電子回複)的表單;

對rsvp表單的驗證,它将顯示一個“謝謝你”的頁面;

當完成rsvp時,給晚會的主人發送一份電子郵件。

以下小節将增強本章開始已經建立的mvc項目,并實作上述這些特性。讀者可以利用前面已經涉及的内容來完成上述清單中的第一項——将一些html添加到現在的視圖上,以給出晚會的細節。清單2-7顯示了對views/home/index.cshtml檔案所添加的内容。

清單2-7 顯示晚會的細節

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

開發已經開始了。如果運作該應用程式,就會看到晚會的詳情——沒錯,這隻是一個詳情占位符,但可以從中獲得思路(指這個頁面隻是一些簡單的消息,在實際應用中,讀者可以用豐富的内容來替換這裡的消息,故将其說成是占位符——譯者注),如圖2-12所示。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

在mvc中,m代表模型(model)是應用程式最重要的部分。模型是應用程式主體(稱為域,domain)所定義的現實對象、過程以及規則的表示。模型,通常稱為域模型(domain model),含有應用程式域中要建立的c#對象,稱為域對象(domain object)。這些域對象構成了整個應用程式的體系,以及操縱這些對象的方法。視圖和控制器以一緻的方式把這個域暴露給用戶端。一個設計良好的mvc應用程式,必須從設計良好的模型開始,它是随後添加控制器和視圖的焦點(現在國内流行将這裡的“域”稱為“領域”,譯者認為這種術語不妥,但如果讀者不習慣這裡的“域”術語,可以将本書的“域”了解為“領域”——譯者注)。

對于這個partyinvites(晚會邀請)應用程式,不需要複雜的模型,是以将建立一個域類,叫作guestresponse。這種對象将負責存儲、驗證并确認rsvp。

添加模型類

mvc的約定是把建立模型的類放在“models”檔案夾内。在“solution explorer(解決方案資料總管)”視窗中右擊“models”,從彈出菜單中選擇“add(添加)”→“class(類)”,将檔案名設定為“guestresponse.cs”,點選“add(添加)”按鈕,建立這個類。編輯該類的内容,使其與清單2-8吻合。

提示:如果沒有“class(類)”菜單項,那麼可能仍在運作visual studio的調試器。調試器正在運作應用程式期間,visualstudio會限制使用者對項目進行修改。

清單2-8 guestresponse域類

提示:讀者可能已經注意到,willattend屬性是一個nullable(可空的)的bool型,這意味着它可以是true、false或null。本章的2.4.6節将解釋這一原理。

該應用程式的目标之一是要包括一個rsvp的表單,是以需要在index.cshtml視圖中添加一個指向它的連結,如清單2-9所示。

清單2-9**添加一個指向rsvp表單的連結

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

html.actionlink是一個html輔助器方法(helper method),其作用是渲染一個超連結的html标記。mvc架構随帶了一組内建的輔助器方法,它們可以友善地用來渲染html的連結、文本輸入框、單選框、複選框,甚至自定義控件等。這個actionlink方法需要兩個參數:第一個是該連結的顯示文本,第二個是當使用者點選該連結時将要執行的動作。第19~21章将解釋其餘的html輔助器方法。讀者可以在圖2-13中看到添加的這個連結。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

建立動作方法

如果點選這個連結,就會看到一個“404—未找到”的錯誤,這是因為還沒有建立與這個/home/rsvpform位址所對應的方法。可以把一個名為“rsvpform”的方法添加到homecontroller類,如清單2-10所示。

清單2-10 給控制器添加一個新的動作方法

添加一個強類型視圖

本書打算為這個rsvpform動作方法添加一個視圖,但做法稍有不同——建立一個強類型視圖(strongly typed view)。強類型視圖意在渲染一個特定的域類型,而且,如果指定了想使用的類型(本例是guestresponse),mvc将能夠建立便于使用這個類型的便捷手段(指mvc提供了一些輔助器方法,在視圖中可以友善是使用這個類型對象——譯者注)。

注意:在做後面的事情之前,請確定已編譯了mvc項目。如果已經建立了guestresponse類,但未編譯它,mvc将不能為這個類型建立強類型視圖。要編譯應用程式,可以從visual studio的“build(生成)”菜單中選擇“build solution(生成解決方案)”(或簡單地按快捷鍵f6——譯者注)。

在rsvpform動作方法中單擊滑鼠右鍵,從彈出菜單中選擇“add view(添加視圖)”,建立這個視圖。在“add view(添加視圖)”對話框中選中“create a strongly-typed view(建立強類型視圖)”選項,并從下拉清單中選擇guestresponse,取消選中“use a layout or master page(使用布局或母版頁)”複選框,并確定選擇了razor作為視圖引擎,在“scaffold template(支架模闆)”中選擇“empty(空模闆)”,如圖2-14所示。

點選“add(添加)”按鈕,visual studio将建立一個名為rvspform.cshtml的新視圖檔案,并打開它以便編輯。清單2-11是它的最初内容。讀者可能會注意到,這是另一種骨架形式的html檔案,它含有razor表達式@model。稍後會看到,這個@model是強類型視圖的關鍵,也是為視圖提供友善的關鍵。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

清單2-11 rsvpform.cshtml檔案的最初内容

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

現在,強類型視圖已經建立了。可以擴建rsvpform.cshtml的内容,将其制作成編輯guestresponse對象的html表單。編輯該視圖,使它如清單2-12所示。

清單2-12 建立一個表單視圖

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

對于guestresponse模型類的每一個屬性,可使用一個html輔助器方法來渲染一個适當的html的input控件。這些方法讓使用者能夠用lambda(讀音同希臘字母λ的發音(拉姆達)——譯者注)表達式來選擇與input元素有關的屬性,如下所示。

<code>@html.textboxfor(x =&gt; x.phone)</code>

這個html的textboxfor輔助器方法生成html的input元素,将其type參數設定為text,并把id和name标簽屬性設定為phone,phone是所選域類的屬性名,如下所示(于是為模型屬性phone生成了一個文本框,該文本框是一個html的input元素——譯者注)。

<code>&lt;input id="phone" name="phone" type="text" value="" /&gt;</code>

這種靈活的特性是能夠起作用的,因為這個rsvpform視圖是強類型的,而且已經告訴了mvc——guestresponse是希望該視圖所渲染的類型。是以,html輔助器方法能夠通過@model表達式推斷出使用者想根據哪種資料類型來讀取屬性。

如果不熟悉c#的lambda表達式,不用着急,本書将在第4章提供一個概覽。不過,替代運用lambda表達式的另一種辦法是,将模型類型的屬性名訓示為一個字元串,如下所示。

<code>@html.textbox("email")</code>

可以發現,lambda表達式技術可以防止人們輸錯模型類型的屬性名,因為visaul studio會彈出智能感應,并讓人們自動地選取屬性,如圖2-15所示。

另一個友善的輔助器方法是html.beginform,它生成一個回遞給動作方法的html表單元素(

元素)。由于沒有給這個輔助器方法傳遞任何參數,于是它假設使用者是想回遞給同樣的url。一個整潔的技巧是把它封裝在一個c#的using語句中,如下所示。

正常情況下,像這樣運用using語句,會在對象超出範圍時,確定對這個對象進行了清理(清理對象意指收回對象所占用的資源——譯者注)。例如,這通常用于資料庫連接配接,以確定查詢完成後盡快關閉這個連接配接(此處的using關鍵詞與在一個類中引用命名空間的那種using不同)。

這裡并不是清理對象(上一段文字是指“正常情況下”——譯者注),而是html.beginform輔助器在它超出範圍時關閉html的form元素。這意味着,html.beginform輔助器方法會建立form元素的兩部分(指

元素的開标簽和閉标簽——譯者注),如下所示。

<code>&lt;form action="/home/rsvpform" method="post"&gt;</code>

<code>..._表單内容放在這兒_...</code>

<code>&lt;/form&gt;</code>

即使不熟悉c#的對象清理,也不必擔心。這裡的關鍵是示範如何用html輔助器方法建立一個表單。當運作這個應用程式并點選“rsvp now(現在回複)”連結時,便可以看到rsvpform視圖中的這個表單,如圖2-16所示。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

注意:由于這不是一本關于css或web設計的書,本書的大部分内容将把示例示範成流行的樣式(雖然本書更喜歡把它說成“經典樣式”,但感覺不太對)。mvc視圖生成十分整潔且純淨的html,而且使用者可以完全控制元素的布局,以及用表單進行指派的類,是以,使用設計工具或現成的模闆,讓mvc項目美觀是沒有問題的。

此時還沒有告訴mvc,将表單遞交給伺服器時要做什麼。此刻,點選“submit rsvp”按鈕隻是清除了表單中已經輸入的值。這是因為,該表單會回遞給home控制器中的rsvpform動作方法,它隻是告訴mvc再次渲染這個視圖。

注意:讀者可能會感到奇怪,視圖被再次渲染時,輸入的資料消失了。如果有這種感覺,可能是因為一直在使用asp.net web form開發應用程式,web form在這種情況下,資料是自動保留的。下面的内容将很快示範如何用mvc取得同樣的效果。

為了接收并處理表單所遞交的資料,本書打算做一件聰明的事情。添加第二個rsvpform動作方法,以形成如下作用。

一個方法用于響應http的get請求:get請求是某人點選一個連結時浏覽器正常發出的請求。當有人第一次通路/home/rsvpform時,這個動作版本負責顯示最初的空白表單。

一個方法用于響應http的post請求:預設情況下,用html.beginform()渲染的表單是由浏覽器作為一個post請求遞交的。這個動作版本負責接收所遞交的資料,并決定用它做什麼。

以獨立的c#方法分别處理get和post請求,有助于保持代碼整潔,因為這兩種方法有不同的職責。兩種方法都由同樣的url進行調用,但mvc確定會根據使用者處理的是get請求,還是post請求,來調用合适的方法。清單2-13顯示了需要對homecontroller類所進行的修改。

清單2-13 添加一個支援post請求的動作方法

此時,已經把httpget注解屬性加到了現在的rsvpform動作方法上。這告訴mvc,這個方法應該僅用于get請求。然後添加了一個重載的rsvpform方法,它帶有一個guestresponse參數,并運用了httppost注解屬性。該注解屬性告訴mvc,這個新方法将處理post請求。注意,這裡已經引入了partyinvites.models命名空間。這樣,可以直接使用guestresponse模型類型,而不需要使用這個類的限定名。在以下幾節中,本書将解釋對該清單所做的添加是如何工作的。

注:本書涉及一些不同含義的“屬性”,這些屬性在英文中有些稱為property,有些則稱為attribute,但中文均應當把它們稱為屬性。為了對這些屬性加以差別,本書在翻譯文字中對這些屬性采用了相應的專門術語:① 把類或對象的property稱為屬性;② 把[httpget]這樣的attribute稱為注解屬性(annotation attribute),注解屬性有很多種,除這裡的[httpget]和[httppost]外,本章稍後介紹的驗證規則也是一種注解屬性;③ 把html元素的attributes稱為标簽屬性(attributes of html tags),如<code>&lt;input id= "phone" name="phone" type="text" value="" /&gt;</code>,其中id、name、type、value都稱為标簽屬性——譯者注

1.使用模型綁定

rsvpform動作方法的第一個重載渲染和前面同樣的視圖,它生成圖3-16所示的表單。第二個重載由于其參數變得更為有趣,但已給定該動作方法是響應http的post請求而被調用的,也已給定guestresponse類型是一個c#類,那麼,這兩者是如何連接配接的呢?

答案是模型綁定(model binding),這是一個非常有用的mvc特性,憑借它可以解析輸入資料,并用“鍵/值”對填充域模型類型的屬性。這一過程與使用html輔助器方法是相反的。即,當建立發送給用戶端的表單資料時,(html輔助器方法)生成了html的input元素,其中id和name标簽屬性的值來自于模型類的屬性名。

與此相反,通過模型綁定,會用input元素名來設定模型類執行個體中屬性的值(其實這句話說得不完全正确,應當是用input的元素名和值來設定模型類執行個體中的屬性值,以便通過使用者在表單的各個input元素中輸入的值來構造一個模型類執行個體——譯者注),然後該執行個體被傳遞給處理post的動作方法(簡單地說,輔助器的作用是用模型類的資料來建立html元素,而模型綁定是用表單中輸入的資料建立模型對象。是以說,模型綁定與輔助器方法的作用是相反的——譯者注)。

模型綁定是一個功能強大且可定制的特性,它消除了處理http請求的煩瑣,使開發者能夠用c#對象進行工作,而不是處理request.form[]和request.quertystring[]的值。作為參數被傳遞給動作方法的guestresponse對象自動地被填充了表單字段的資料。第22章将深入研究模型綁定,包括如何對它進行定制的細節。

2.渲染其他視圖

rsvpform動作方法的第二個重載也示範了如何才能告訴mvc去渲染一個對請求進行響應的特定視圖。以下是相關語句。

<code>return view("thanks", guestresponse);</code>

這個對view方法的調用告訴mvc,查找并渲染一個名為“thanks”的視圖,并把guestresponse對象傳遞給這個視圖。為了建立所指定的這個視圖,右擊homecontroller中的一個方法,從彈出菜單中選擇“添加視圖”,将視圖名設定為thanks,如圖2-17所示。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

由于打算建立另一個強類型視圖,是以,在“add view(添加視圖)”對話框中選中“create a strongly-typed view(建立強類型視圖)”複選框。為這個視圖所選擇的資料類必須與用view方法傳遞給這個視圖的類相對應,故從下拉清單中選擇guestresponse。確定“use a layout or master page(使用布局或母版頁)”複選框未選中,“view engine(視圖引擎)”設定為razor。

點選“add(添加)”按鈕,建立這個新視圖。因為該視圖是與home控制器相關聯的,故mvc會将此視圖建立為~/views/home/thanks.cshtml。編輯此新視圖,使之與清單2-14比對——本書已高亮了需要添加的标記。

清單2-14 thanks視圖

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

該thanks視圖使用razor并根據guestresponse屬性的值來顯示内容,guestresponse是在rsvpform動作方法中傳遞給view方法的。razor的@model操作符訓示了這個強類型視圖的域模型類型。為了通路這個域對象中某個屬性的值,要使用model.propertyname(即model.&lt;屬性名&gt;——譯者注)。例如,要獲得name屬性的值,調用model.name。如果對razor文法尚不了解,不用擔心——本書将在第5章解釋razor。

既然已經建立了thanks視圖,便有了一個以mvc處理表單的簡單運作示例。

在visual studio中啟動該應用程式,點選“rsvp now(現在回複)”連結,對表單添加一些資料,然後點選“submit rsvp(遞交回複)”按鈕。讀者将看到圖2-18所示的結果(如果姓名不是joe,并且表明不出席,顯示會有所不同)。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

現在,到了對應用程式添加驗證的時候了。如果不做此事,使用者可能會輸入無意義的資料,甚至遞交一個空白表單。

在mvc應用程式中,驗證典型地運用于域模型而不是使用者界面。這意味着,在一個地方定義驗證條件,會在運用模型類的任何地方生效。asp.net mvc支援驗證規則聲明,驗證規則是以system.componentmodel.dataannotations命名空間中的注解屬性進行定義的。清單2-15示範了如何把這些注解屬性運用于guestresponse模型類。

清單2-15 對guestresponse模型類運用驗證

驗證規則顯示為黑體。mvc會偵測這些驗證注解屬性,并在模型綁定過程中用它們來驗證資料。注意,這個清單已經引入了含有驗證的命名空間,是以不需要用限定名來引用它們。

提示:正如之前說明的,本書對willattend屬性使用了一個可空的(nullable)bool型。這樣做是為了可以運用required驗證注解屬性。如果使用一個正常的bool型,那麼,通過模型綁定所接收的值隻能是true或false,但不能判斷使用者是否已選擇了一個值。一個可空的bool型有三個可能的值:true、false和null。如果使用者尚未選擇,系統會預設用null來表示,這會讓required注解屬性能夠報告一個驗證錯誤。

讀者可以在控制器類中用modelstate.isvalid屬性來檢查是否有驗證問題。清單2-16示範了在處理post的rsvpform動作方法中,如何運用modelstate.isvalid。

清單2-16 檢查表單驗證錯誤

如果沒有驗證錯誤,便告訴mvc渲染thanks視圖,這就像先前所做的那樣。如果有驗證錯誤,則通過調用不帶參數的view方法,來重新渲染rsvpform視圖。

在有錯誤時僅顯示表單并不十分有用——需要給使用者提供一些訓示,告訴他們有什麼問題以及為什麼不能接受表單遞交。通過在rsvpform視圖中使用html.validationsummary(驗證摘要)輔助器方法可以完成這種工作,如清單2-17所示。

清單2-17 使用html.validationsummary輔助器方法

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

如果沒有錯誤,這個html.validationsummary方法會在表單中建立一個隐藏的清單條目占位符;否則,mvc會使這個占位符成為可見,并添加由驗證注解屬性所定義的錯誤消息。讀者可以在圖2-19中看到這是如何顯示的。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

直到運用于guestresponse類的所有驗證限制都得到滿足,使用者才會看到thanks視圖。注意,在表單中輸入的資料是被保留的,并且,當帶有驗證摘要的視圖被重新渲染時,這些資料會再次顯示出來。這是通過模型綁定所得到的另一個好處。

注:曾經用過asp.net web form的讀者,應該知道web form有一種“伺服器控件”的概念。伺服器控件通過把值序列化到一個叫作“__viestate”的隐藏字段來保持狀态。asp.net mvc模型綁定與web form的伺服器控件、回遞或視圖狀态等概念無關。asp.net mvc不會把隐含字段__viewstate注入到渲染的html頁面中。

高亮無效字段

建立文本框、下拉清單,以及其他元素的html輔助器方法有一個十分靈活的特性,可以用來與模型綁定相關聯。保留使用者在表單中的輸入資料的同樣機制,也可以用來高亮驗證檢查失敗的個别字段。

當模型類屬性驗證失敗時,html輔助器方法可以生成稍有不同的html。例如,以下是html.textboxfor(x =&gt; x.name)在沒有驗證錯誤時生成的html。

<code>&lt;input data-val="true" data-val-required="please enter your name" id="name" name="name"</code>

<code>type="text" value="" /&gt;</code>

而當使用者未提供一個值時(這是一個驗證錯誤,因為對guestresponse模型類中的name屬性運用了required注解屬性),以下是同樣的調用所生成的html。

<code>&lt;input class="input-validation-error"** data-val="true" data-val-required="please enter yourname" id="name" name="name" type="text" value="" /&gt;</code>

上述代碼已經以黑體高亮了其差異。輔助器方法添加了一個值為“input-validation-error”的class标簽屬性。通過建立樣式表可以利用這一特性,該樣式表可以為這個class以及其他html輔助器方法所生成的class設定一些不同的css樣式(這樣就可以對不同的class值設定一些不同的顯示效果——譯者注)。

mvc項目的約定是,靜态内容(如css樣式表等)要放入名為content的檔案夾中。在“solution explorer(解決方案資料總管)”中右擊“partyinvites”項目,從彈出菜單中選擇“add(添加)”→“new folder(新檔案夾)”,便可以建立content檔案夾。右擊“content”,選擇“add(添加)”→“new item(新項)”,在“add new item(添加新項)”對話框中選取“style sheet(樣式表)”,便可建立樣式表。将樣式表取名為site.css,這是使用一個mvc模闆但不是empty建立項目時,visual studio會自動建立的一個網站樣式表檔案。讀者可以在清單2-18中看到content/site.css檔案的内容(該清單的内容需要讀者輸入或粘貼進去,并非是自動生成的——譯者注)。

清單2-18 content/site.css檔案的内容

為了使用該樣式表,可以在rsvpform視圖的頭部(

元素中——譯者注)添加一個新的引用,如清單2-19所示。給視圖添加link元素就像正常的靜态html檔案。

清單2-19 對rsvpform視圖添加連結元素

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

提示:曾用過mvc 3的讀者可能會料想到,本書會将href标簽屬性指定為@href("~/content/site.css"),或@url.content("~/content/site.css"),使css檔案添加到視圖。但對于mvc 4,razor自動地檢測以~/開始的标簽屬性,并自動插入@href或者@url調用。

現在,當遞交會引發驗證錯誤的資料時,會顯示更明顯的驗證錯誤,如圖2-20所示。

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

這個示例應用程式的最後需求是,将完成了的rsvp用電子郵件發給邀請的賓客和晚會的組織者。可以添加一個動作方法,使用.net架構的e-mail類來建立并發送一份郵件消息,以完成這一任務。但在這裡,本書打算使用webmail輔助器方法。這不是mvc架構的一部分,但它确實能完成這個例子,而不必建立另一個發送郵件的表單。

注:這裡使用webmail輔助器方法,是因為它可以輕松地示範發送一份郵件消息。然而,人們通常更喜歡把這個功能放在一個動作方法中。第3章将在描述mvc體系結構模式時,對此進行解釋。

此處希望在渲染thanks視圖時發送這份郵件消息。清單2-20顯示了需要進行的修改。

清單2-20 使用webmail輔助器

《精通 ASP.NET MVC 4》----2.4 建立一個簡單的資料錄入應用程式

清單2-16添加了一段razor代碼塊,它用webmail輔助器來配置郵件伺服器的細節,包括伺服器名、伺服器是否需要ssl連接配接,以及賬号細節。一旦配置了所有這些細節,就可以用webmail.send方法來發送這封郵件了。

将所有關于e-mail的代碼都封裝在一個try...catch塊中,于是,如果不能發送郵件,則可以向使用者發出警告。做這件事的辦法是,把一個文本塊添加到thanks視圖的輸出。一個更好的辦法是,當不能發送郵件消息時,顯示一個獨立的錯誤視圖,但這裡希望這第一個mvc應用程式盡量簡單。

本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。

繼續閱讀