天天看點

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

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

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

假設一個朋友決定舉行一個“新年除夕晚會”,于是她請筆者為其建立一個web應用程式,以便讓受邀人進行電子回複<code>(rsvp)</code>。她的要求有以下4個關鍵特性。

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

一個可以用來進行電子回複<code>(rsvp)</code>的表單。

對<code>rsvp</code>表單的驗證,它将顯示一個“感謝你”的頁面。

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

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

清單2-8 在<code>index.cshtml</code>檔案中顯示晚會的細節

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

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

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

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

對于<code>partyinvites</code>(晚會邀請)應用程式,不需要複雜的模型。因為這是一個簡單的應用程式,隻需要建立一個域類(可以稱為<code>guestresponse</code>),由它負責存儲、驗證并确認<code>rsvp</code>。

添加模型類

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

提示:

如果沒有<code>“class(類)”</code>菜單項,可能是仍在運作visual studio的調試器。因為調試器正在運作應用程式期間,visual studio會限制對項目進行修改。

清單2-9 <code>guestresponse.cs</code>檔案中定義的<code>guestresponse</code>域類

你可能已經注意到,<code>willattend</code>屬性是一個可空的(<code>nullable</code>)<code>bool</code>型,這意味着它的取值可以是true、false或null。本章稍後的“添加驗證”小節将解釋其基本原理。

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

清單2-10 在<code>index.cshtml</code>中添加一個指向rsvp表單的連結

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

<code>html.actionlink</code>是一個html的輔助器方法(helper method)。mvc架構附帶了一組内置的輔助器方法,它們可以友善地用來渲染html的連結、文本輸入框、複選框、選擇框以及其他種類的内容。這個<code>actionlink</code>方法有兩個參數:第一個是該連結的顯示文本,第二個是使用者單擊該連結時将要執行的動作。第21~23章将解釋完整的html輔助器方法集合。啟動該項目可以看到該輔助器所建立的連結,如圖2-15所示。

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

如果在浏覽器中将滑鼠移到這個連結上,可以看到該連結指向<code>http://&lt; 你的伺服器 &gt;/home/ rsvpform。html.actionlink</code>方法已經檢測了應用程式的url路由配置,并得出<code>/home/rsvpform</code>是一個指向<code>homecontroller</code>控制器上<code>rsvpform</code>動作的url。

與傳統的<code>asp.net</code>應用程式不同,mvc的url并不對應于實體檔案。每個動作方法有它自己的url,而mvc使用<code>asp.net</code>的路由系統将這些url轉換成動作。

1.建立動作方法

如果單擊該連結,會看到一個<code>“404not found(404—未找到)”</code>的錯誤,這是因為還沒有建立與這個<code>/home/rsvpform</code>位址所對應的動作方法。此時,可以在<code>homecontroller</code>類中添加一個名稱為<code>“rsvpform”</code>的方法來完成這一工作,如清單2-11所示。

清單2-11 在<code>homecontroller.cs</code>檔案中添加一個新的動作方法

2.添加強類型視圖

這裡打算為<code>rsvpform</code>動作方法添加一個視圖,但采取了稍有不同的方式——建立一個強類型視圖(strongly typed view)。強類型視圖意在渲染一個特定的域類型,而且,如果指定了想使用的類型(本例是<code>guestresponse</code>),mvc将能夠建立便于使用這個類型的方法(指mvc提供了一些便捷的方法,可以在視圖中友善地使用這個類型對象)。

注意:

在做進一步工作之前,要確定已編譯了mvc項目。如果已經建立了<code>guestresponse</code>類,但未進行編譯,mvc将不能為這個類型建立強類型視圖。要編譯應用程式,可以從<code>visual studio的“build(生成)”</code>菜單中選擇<code>“build solution(生成解決方案)”</code>(或簡單地按快捷鍵f6)。

在代碼編輯器中右擊<code>rsvpform</code>方法,從彈出的菜單中選擇<code>“add view(添加視圖)”</code>,打開<code>“add view(添加視圖)”</code>對話框,確定将<code>“view name(視圖名)”</code>設定為<code>“rsvpform”</code>,将<code>“template(模闆)”</code>設定為<code>“empty(空)”</code>,并從<code>“model class(類模闆)”</code>字段的下拉清單中選擇<code>“guestresponse(partyinvites. models)”</code>,讓<code>“view options(視圖選項)”</code>中的複選框處于未選狀态,如圖2-16所示。

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

單擊<code>“add(添加)”</code>按鈕,<code>visual studio将在views</code>`<code>home</code>`檔案夾中建立一個新的檔案,其名稱為<code>rsvpform.cshtml</code>,并打開它,以便編輯。從清單2-12中可以看到它的最初内容。這是另一種結構形式的html檔案,它包含了一個@model的razor表達式。過一會兒便會明白,這是強類型視圖,并是為視圖提供便利的關鍵。

清單2-12 <code>rsvpform.cshtml</code>檔案的最初内容

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

在建立視圖時,所選擇和勾選的選項決定了視圖檔案的初始内容,其他沒什麼作用。例如,你可以将正常視圖修改成強類型視圖,隻需在代碼編輯器中添加或去除@model訓示符即可。

現在已經建立了強類型視圖,可以擴建這個<code>rsvpform.cshtml</code>的内容,将其制作成編輯<code>guestresponse</code>對象的html表單,如清單2-13所示。

清單2-13 在<code>rsvpform.cshtml</code>檔案中建立表單視圖

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

這裡對<code>guestresponse</code>模型類的每一個屬性都使用了一個html輔助器方法,以便渲染一個适當的html的<code>input</code>控件。這些輔助器方法能夠用一個<code>lambda</code>(讀音同希臘字母λ的發音(拉姆達))表達式來選擇與<code>input</code>元素有關的屬性,如下所示。

這個textboxfor輔助器方法會生成一個<code>input</code>元素的html,将該元素的<code>type</code>參數設定為<code>“text”</code>,id和name标簽屬性設定為<code>“phone”</code>,phone是所選域類的屬性名,如下所示(于是為模型屬性phone生成了一個文本輸入框的html标記)。

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

這種靈活的特性是能夠起作用的,因為rsvpform視圖是強類型的,而且已經告訴mvc,<code>guestresponse</code>是希望用該視圖渲染的類型。這為html輔助器方法提供了所需的資訊,使其能夠了解從@model表達式所讀取的屬性是哪一種資料類型。

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

不難發現,<code>lambda</code>表達式技術可以防止輸錯模型類型的屬性名,因為<code>visual studio</code>能夠自動地彈出智能感應并選取屬性,如圖2-17所示。

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

另一個便利的輔助器方法是<code>html.beginform</code>,它生成一個回遞給動作方法的html表單元素(&lt; form &gt;元素)。這裡未給輔助器方法傳遞任何參數,于是它假設要回遞的目标是請求此html文檔的同一個url。一個整潔的技巧是将它封裝在一個c#的<code>using</code>語句中,如下所示。

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

但這裡并不是清理對象(上一段文字是指“正常情況下”),而是<code>html.beginform</code>輔助器在它超出範圍時關閉html的<code>form</code>元素。這意味着,<code>html.beginform</code>輔助器方法會建立<code>form</code>元素的兩部分(指&lt; form &gt;元素的開标簽和閉标簽),如下所示。

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

如果不熟悉c#的對象清理,不必擔心。這裡的關鍵是示範如何用html輔助器方法建立一個表單。

visual studio會以一種有助的嘗試,根據目前正在編輯的視圖,讓浏覽器請求一個url。但這是一個不穩定的特性,在編輯其他類型的檔案時就不能生效了,而且在大多數複雜的web應用程式中,也不能在任意位置進行恰當的跳轉。

為了對浏覽器的請求設定一個固定的url,可以從visual studio的<code>“project(項目)”</code>菜單中選擇<code>“partyinvites properties(partyinvites屬性)”</code>,然後選擇<code>“web”</code>,并選中<code>“start action(啟動操作)”</code>分類中的<code>“specific page(特定頁面)”</code>選項,如圖2-18所示。不必在該字段中輸入一個值——visual studio會請求項目的預設url,即指向<code>home</code>控制器的<code>index</code>動作方法(第15~16章将示範如何使用url路由系統來修改這種預設的映射)。

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

當運作應用程式并單擊<code>“rsvp now(現在回複)”</code>連結時,可以看到<code>rsvpform</code>視圖中的這個表單,結果如圖2-19所示。

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

這裡尚未告訴mvc,将表單遞交給伺服器時要做什麼。此刻,單擊<code>“submit rsvp”</code>按鈕隻是清除了表單中已經輸入的值。這是因為該表單會回遞給home控制器中的<code>rsvpform</code>動作方法,這隻是告訴<code>mvc</code>再次渲染該視圖。

注:

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

為了接收并處理表單所遞交的資料,這裡打算使用一個聰明的特性。添加第二個<code>rsvpform</code>動作方法,以形成如下作用。

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

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

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

清單2-14 在<code>homecontroller.cs</code>檔案中添加一個支援post請求的動作方法

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

1.使用模型綁定

第一個重載的rsvpform動作方法渲染之前的同一個視圖(rsvpform.cshtml檔案),以生成如圖2-19所示的表單。

第二個重載由于其參數變得較為有趣,但已給定該動作方法是響應http的post請求而被調用的,也已給定<code>guestresponse</code>類型是一個c#類,那麼這兩者是如何連接配接的呢?

答案是模型綁定(model binding),這是一個非常有用的mvc特性,憑借它可以解析輸入資料,并将http請求中的“鍵/值”用來填充域模型類型的屬性。這一過程與使用html輔助器的方法是相反的,即,在建立發送給用戶端的表單資料時,生成的是html的<code>input</code>元素,其中的<code>id</code>和<code>name</code>标簽屬性的值來自于模型類的屬性名(這裡描述的是html輔助器的作用,該作用是将模型資料轉換成html資訊,即采用“模型→html”的方式進行資料轉換)。

與此相反,對于模型綁定,會用<code>input</code>元素的名稱來設定模型類執行個體中屬性的值(其實這句話說得不完全正确,應當是用<code>input</code>的元素名和值來設定模型類執行個體中的屬性值,以便通過使用者在表單的各個<code>input</code>元素及其輸入的值來構造一個模型類執行個體),然後該執行個體被傳遞給處理<code>post</code>的動作方法(這裡描述的是模型綁定的作用,故模型綁定是利用表單元素及其輸入的資料來建立模型對象,即采用“html→模型”的方式進行資料轉換。是以說,模型綁定與輔助器方法的作用是相反的)。

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

2.渲染其他視圖

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

這個對view方法的調用告訴mvc,查找并渲染一個名稱為<code>“thanks”</code>的視圖,并對該視圖傳遞<code>guestresponse</code>對象。為了建立所指定的視圖,可以右擊<code>homecontroller</code>中的任意一個方法,并從彈出的菜單中選擇<code>“add view(添加視圖)”</code>,使用<code>“add view(添加視圖)”</code>對話框建立一個名稱為“thanks”的強類型視圖,該視圖以<code>guestresponse</code>為模型類,并基于empty模闆(如果需要,請參閱前述“添加強類型視圖”小節的步驟)。visual studio将此視圖建立為<code>views/home/thanks.cshtml</code>。編輯此新視圖,使其與清單2-15比對,其中已加黑顯示所需添加的标記。

清單2-15 <code>hanks.cshtml</code>檔案内容

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

這個thanks視圖将使用razor并根據<code>guestresponse</code>屬性的值來顯示内容,<code>guestresponse</code>是在<code>rsvpform</code>動作方法中傳遞給<code>view</code>方法的。razor的@model表達式訓示了這個強類型視圖的域模型類型。為了通路這個域對象中某個屬性的值,要使用<code>model.</code>&lt; 屬性名 &gt;的方式。例如,要獲得<code>name</code>屬性的值,需調用<code>model.name</code>。如果對razor文法尚不了解,不用擔心,第5章将做詳細解釋。

既然已經建立了thanks視圖,便有了一個以mvc處理表單的簡單運作示例。在visual studio中啟動該應用程式,單擊<code>“rsvp now</code>(現在回複)”連結,在表單中添加一些資料,然後單擊<code>“submit</code>rsvp``(遞交回複)”按鈕,便會看到如圖2-20所示的結果(當然,如果姓名不是joe,或者說不出席晚會,顯示會有所不同)。

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

現在,到了對應用程式添加驗證的時候了。沒有驗證,使用者可能會輸入無意義的資料,甚至遞交一個空白的表單。在mvc應用程式中,驗證典型地運用于域模型,而不是使用者界面。這意味着可以在一個地方定義驗證條件,而在運用模型類的任何地方生效。asp.net mvc支援驗證規則聲明(declarative validation rules),這是以<code>system.componentmodel.dataannotations</code>命名空間中的注解屬性進行定義的,意即,驗證限制是使用标準的c#注解屬性特性來表示的。清單2-16示範了如何将這些注解屬性運用于<code>guestresponse</code>模型類。

清單2-16 在<code>guestresponse.cs</code>檔案中運用驗證

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

正如前面曾說明的,對于<code>willattend</code>屬性,使用了可空的<code>bool</code>型。這麼做之後,便能夠運用<code>required</code>驗證注解屬性了。如果使用的是一個正常的<code>bool</code>型,則通過模型綁定所接收的值隻能是<code>true或false</code>,于是便不能判斷使用者是否已選擇了一個值。一個可空的<code>bool</code>型有3個可能的值:<code>true、false和null</code>。如果使用者尚未選擇,系統會預設用<code>null</code>來表示,這會讓<code>required</code>注解屬性能夠報告一個驗證錯誤。這是mvc架構如何優雅地将c#特性與html和http相融合的一個很好的示例。

可以在控制器類中使用<code>modelstate.isvalid</code>屬性來檢查是否有驗證問題。清單2-17示範了這種事情的做法,這是在<code>home</code>控制器類的啟用<code>post</code>的<code>rsvpform</code>動作方法中實作的。

清單2-17 在<code>homecontroller.cs</code>檔案中檢查表單驗證錯誤

如果沒有驗證錯誤,便讓mvc渲染<code>thanks</code>視圖,就像前面所做的那樣。如果有驗證錯誤,則通過調用不帶參數的<code>view</code>方法重新渲染<code>rsvpform</code>視圖。

在有錯誤時,僅顯示表單并不十分有用,還需要給使用者提供一些訓示,告訴他們有什麼問題,以及為什麼不能接受他們所遞交的表單。其實作辦法是在<code>rsvpform</code>視圖中使用<code>html. validationsummary</code>(驗證摘要)輔助器方法,如清單2-18所示。

清單2-18 在<code>rsvpform.cshtml</code>檔案中使用<code>html.validationsummary</code>輔助器方法

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

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

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

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

如果曾用過<code>asp.net web form</code>,應該知道<code>web form</code>有一種伺服器控件的概念。伺服器控件能夠保持狀态,其實作方式是将序列化的值儲存到一個叫做<code>“_</code>viewstate”<code>的隐藏字段中。</code>asp.net mvc<code>的模型綁定與web form的伺服器控件、回遞或視圖狀态等概念無關。</code>asp.net mvc<code>不會将隐藏字段</code>_<code>viewstate</code>注入到所渲染的html頁面。

高亮顯示無效字段

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

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

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

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

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

這裡以粗體高亮了其差異:輔助器方法給input元素添加了一個值為<code>“input-validation-error”</code>的class标簽屬性。通過建立樣式表便可以利用這一特性,該樣式表可以為這個class以及其他html輔助器方法所生成的class設定一些不同的css樣式(這樣就可以對不同的class值設定一些不同的顯示效果)。

mvc項目的約定是:将靜态内容(如css樣式表等)放在名稱為content的檔案夾中。在<code>“solution explorer</code>(解決方案資料總管)”中右擊<code>“partyinvites”</code>項目,從菜單中選擇<code>“add(添加)”→“new folder(新檔案夾)”</code>,将其命名為<code>“content”</code>,便可以建立該檔案夾。

為了建立css檔案,右擊建立的“content”檔案夾,從菜單中選擇<code>“add(添加)”→“newitem(新項)”</code>,在項目模闆集合中選擇<code>“style sheet(樣式表)”</code>。将此檔案的名稱設定為<code>“styles.css”</code>,如圖2-22所示。

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

單擊<code>“add(添加)”</code>按鈕,visual studio便會建立<code>“content/styles.css”</code>檔案。設定新檔案的内容,使其與清單2-19吻合。

清單2-19 <code>styles.css</code>檔案的内容

為了使用該樣式表,可以在<code>rsvpform</code>視圖的頭部(&lt; head &gt;元素中)添加一個新的引用,如清單2-20所示。給視圖添加<code>link</code>元素與在正常的靜态html檔案中的做法一樣。不過,第27章将示範捆綁包(bundle)特性,它能夠對javascript和css樣式表進行整理,并能通過一個單一的http請求将這些内容發送給浏覽器。

可以從<code>“solution explorer</code>(解決方案資料總管)”中拖曳javascript和css檔案,将它們放到代碼編輯器中。visual studio能夠對所選的這些檔案自動地建立<code>script</code>和<code>link</code>元素。

清單2-20 在<code>rsvpform.cshtml</code>檔案中添加link元素

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

從mvc 3直接轉向mvc 5的人可能會認為,為了在視圖中添加css檔案,需要将這裡的href标簽屬性指定為<code>@href("~/content/site.css")</code>或@<code>url.content("~/content/site.css")</code>。但自從mvc 4開始,razor已經能夠檢測以“~/”開始的标簽屬性,并自動地插入@href或者@url調用。

利用該樣式表,在遞交會引發驗證錯誤的資料時,會顯示更為明顯的驗證錯誤,如圖2-23所示。

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

至此,除了即将要實作的發送電子郵件功能以外,該應用程式的基本功能也已就緒,但其整體外觀很糟糕。雖然這是一本專注于伺服器端開發的書籍,但是微軟公司已經采納了許多開源庫,并将它們納入到了visual studio的項目模闆之中。

筆者不是這些模闆的“粉絲”,但确實喜歡其中的一些庫,其中之一便是mvc 5新采納的bootstrap。它是最初由twitter開發的一款很好的css庫,如今twitter的運用已經十分廣泛了。

當然,不一定要通過visual studio的項目模闆來使用bootstrap等這樣的一些庫,可以直接從項目網站下載下傳其檔案或使用nuget進行下載下傳。nuget已經被內建到了visual studio之中,它可以通路預先打包的軟體目錄,并自動地對這些軟體包進行下載下傳和安裝。nuget最好的特性之一是它可以管理各個包之間的依賴項,例如,如果安裝bootstrap,則nuget也會下載下傳并安裝bootstrap特性所依賴的jqeury。

1.使用<code>nuget</code>安裝<code>bootstrap</code>

為了安裝<code>bootstrap</code>包,可以從visual studio的“tools(工具)”菜單中選擇“<code>library package manager</code>(庫包管理器)”→“<code>package manager console</code>(包管理器控制台)”,這會打開<code>nuget</code>指令行視窗。在其中輸入以下指令并按enter鍵。

<code>install-package -version 3.0.0 bootstrap</code>

這裡使用了<code>“-version”</code>,用以訓示所需的bootstrap版本為3,它是編寫本書時的最新穩定版。如果不設定<code>“-version”</code>,<code>nuget</code>會下載下傳該包的最新版本,但這裡希望能夠確定按示範的那樣再現示例,是以安裝指定版本有助于保證一緻性。

<code>nuget</code>将下載下傳<code>bootstrap</code>及其依賴項<code>jquery</code>所需的全部檔案。其中的css檔案被添加到“content”檔案夾,同時會建立<code>“scripts”</code>檔案夾(這是mvc放置javascript檔案的标準位置),并在其中放置bootstrap和jquery檔案。同時也會建立一個“fonts”檔案夾,這是<code>bootstrap</code>特性的一個“癖好”——期望一些檔案放在特定的位置。

本章之是以示範bootstrap,是為了說明mvc架構生成的html可以輕而易舉地用于一些流行的css和javascript庫。然而,本書不想偏離伺服器端開發的主題,但如果需mvc架構的用戶端開發方面的完整資訊,可參閱筆者著的pro asp.net mvc 5 client,該書于2014年由apress出版。

2.設定index視圖

清單2-21 在<code>index.cshtml</code>檔案中添加<code>bootstrap</code>

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

這裡已添加了<code>link</code>元素,以引用content檔案夾中的<code>bootstrap.css</code>和<code>bootstrap-theme.css</code>檔案。這些是為引用bootstrap庫提供的css基本樣式所需的檔案,另外在scripts檔案夾中還有一個相應的javascript檔案,但本章不需要用到它。此處還定義了一個<code>style</code>元素,在其中設定了<code>body</code>元素的背景色和一個用于a元素的文本樣式。

你可能會注意到,<code>content</code>檔案夾中的每一個bootstrap檔案都有一個帶有“min”字首的配對檔案,例如,<code>bootstrap.css和bootstrap.min.cs</code>。将應用程式部署到産品環境中時,這是壓縮javascript和css檔案的通用做法,即它是一個删除所有空格符的過程。就javascript而言,它會用較短的标簽來替換函數及變量名。這種壓縮的目的是為了減少對浏覽器遞送内容時所需的帶寬量。第27章将描述自動管理這一過程的asp.net特性。對于本章以及本書的大多數章節而言,将使用其中的正常檔案,這是在開發和測試期間的正常方法。

引入bootstrap樣式并定義一些自己的樣式後,需要對自己的元素設定樣式。這是一個簡單的示例,是以隻需要使用3個<code>bootstrap css的class:text-center、btn和btn-success</code>。<code>text-center</code>可以将元素及其子元素的内容居中;btn可以将按鈕、input或a元素的樣式設定為漂亮的按鈕,而<code>btn-success</code>則可以指定按鈕所用的顔色範圍。按鈕的顔色取決于所用的主題,這裡使用了預設主題(由<code>bootstrap-theme.css</code>檔案進行定義),但通過線上搜尋,有無數的替代品。可以從圖2-24中看到所形成的效果。

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

顯而易見,筆者不是一名web設計師。事實上,當筆者還是一個孩子時,就經常逃藝術基礎課,這足以說明筆者缺少藝術天分。結果筆者在數學課程上有了更多的快樂時光,但這也意味着筆者的藝術技能未超過10歲兒童的平均水準。在實際項目中,筆者會尋求專業的幫助來設計和設定内容的樣式。不過,在這個例子中筆者打算獨自完成,盡可能地用<code>bootstrap</code>的限制和一緻性。

3.設定<code>rsvpform</code>視圖的樣式

bootstrap定義了一些能夠運用于設定表單樣式的class。這裡不打算詳細叙述,但可以從清單2-22中看出如何運用這些class。

清單2-22 在<code>rsvpform.cshtml</code>檔案中添加<code>bootstrap</code>

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

本例中bootstrap的<code>class</code>建立了一個帶标題的面闆(panel),目的是提供結構化的布局。為了設定表單的樣式,這裡使用了<code>form-group</code>,用以設定其中<code>label</code>及其關聯的<code>input</code>及<code>select</code>等元素的樣式。

其中的一些元素是使用html輔助器方法建立的,意即,這不是一些靜态預定義的元素,以便能夠運用所需的<code>form-control</code>的<code>class</code>。但幸運的是,輔助器方法帶有一個可選的對象參數,該參數可以在其所建立的元素上指定标簽屬性,如下所示。

這裡使用了c#的匿名類型特性建立這一對象,匿名類型将在第4章中進行描述。這裡的作用是訓示,應該在這個<code>textboxfor</code>輔助器生成的元素上将class屬性設定為<code>“form-control”</code>。由該對象定義的屬性用于對html元素添加标簽屬性,class是c#語言的保留字,是以使用了字首@。這是一個标準的c#特性,以便在表達式中能夠使用關鍵字。可以從圖2-25看到該樣式的結果。

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

4.設定thanks視圖的樣式

要設定樣式的最後一個視圖是<code>thanks.cshtml</code>,從清單2-23可看出其做法。可以看出,所添加的标記類似于<code>index.cshtml</code>視圖。為了使應用程式易于管理,一個很好的原則是應當盡可能避免代碼和标記的重複。第5章将介紹razor的布局(layout),而第20章将描述分部視圖(partial view)。這兩種方法均可以用來減少标記重複。

清單2-23 将<code>bootstrap</code>運用于<code>thanks.cshtml</code>檔案

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

<code>lead</code>是<code>bootstrap</code>的一種印刷符号樣式,從圖2-26可以看到其效果。

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

該示例應用程式的最後需求是,将已完成的rsvp用電子郵件發給晚會的組織者。其實作辦法是添加一個動作方法,以便使用.net架構的e-mail類來建立并發送一份郵件消息——這恰好是最符合mvc模式的一種技術。但是,這裡打算使用<code>webmail</code>輔助器方法。這種辦法不屬于mvc架構部分,但它确實能夠完成這個示例,而不必建立另一個發送郵件的表單。這裡希望在渲染thanks視圖時發送這份郵件消息。清單2-24顯示了需要進行的修改。

清單2-24 在<code>thanks.cshtml</code>檔案中使用<code>webmail</code>輔助器

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

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

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

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

繼續閱讀