開發人員之所以花費大量時間來重點設計控制器和模型對象,是因為在這些領域中,精心編寫的整潔代碼是開發一個可維護Web應用程式的基礎。 3.1 視圖的作用 視圖的職責是向用戶提供用戶界面。當控制器針對被請求的URL執行完合適的邏輯後,就將要顯示的內容委托給視圖。 不像基於文件的Web框架,比如ASP.N ...
開發人員之所以花費大量時間來重點設計控制器和模型對象,是因為在這些領域中,精心編寫的整潔代碼是開發一個可維護Web應用程式的基礎。
3.1 視圖的作用
視圖的職責是向用戶提供用戶界面。當控制器針對被請求的URL執行完合適的邏輯後,就將要顯示的內容委托給視圖。
不像基於文件的Web框架,比如ASP.NET Web Forms和PHP,視圖本身不會被直接訪 問,瀏覽器不能直接指向一個視圖並渲染它。相反,視圖總是被控制器渲染,因為控制器為它提供了要渲染的數據。
在一些簡單的情況中,視圖不需要或需要很少控制器提供的信息。更常見的情況則是控制器需要向視圖提供一些信息,所以它會傳遞一個數據轉移對象,叫做模型。視圖將這個模型轉換為一個適合顯示給用戶的格式。在ASP.NET MVC中,完成這一過程由兩部分操作,其中一個是檢查由控制器提交的模型對象,另一個是將其內容轉換為HTML格式。
3.2 視圖的基礎知識
在最簡單的情況中,向控制器發出一個請求,控制器返回一個視圖,其實就是一些靜態的HTML。很容易,但是動態性不好。前面說過,視圖提供了一個模板引擎。下麵我們就利用這個模板引擎,從控制器向視圖傳遞少量數據。最簡單的方法就是使用ViewBag。ViewBag具有局限性,但是如果只是向視圖傳遞少數數據,他還是很有用的。
這與前面的Index方法幾乎相同,但是註意控制器將ViewBag.Message屬性值設置成一個字元串。然後再調用return View()。
3.3 理解視圖約定
這一節要介紹ASP.NET MVC如何找到正確的視圖進行渲染,以及如何重寫這個視圖,為一個控制器操作指定特定的視圖。
本章到現在為止介紹的控制器操作簡單地調用return View()來渲染視圖,還不需要指定指定視圖的文件名。可以這麼做,是因為它們利用了ASP.NET MVC框架的一些隱式約定,這些約定定義了視圖選擇邏輯。
當創建新的項目模板時,將會註意到,項目以一種非常具體的方式包含了一個結構化的View目錄。
在每個控制器的View文件夾中,每個操作方法都有一個同名的視圖文件與其對應。這就提供了視圖與操作方法關聯的基礎。
與ASP.NET MVC中的大部分約定設置一樣,這一約定是可以重寫的。如果想要Index操作方法渲染一個不同的視圖,可以向其提供一個不同的視圖名稱。例如:
或
3.4 強類型視圖
通過ViewBag向視圖傳遞少量數據,儘管對於簡單的情況,使用ViewBag很容易,但是處理實際數據時,ViewBag就變得不方便,這時就需要使用強類型視圖。
我們首先看一個不合適使用ViewBag的例子。不必擔心要鍵入這些代碼,它們只是用來進行說明的。
3.4.1 ViewBage的不足
強類型視圖允許設置視圖的模型類型。因此,我們可以從控制器向視圖傳遞一個在兩端都是強類型的模型對象,從而獲得智能感知、編譯器檢查等好處。
對於在視圖中經常使用的名稱空間,一個較好的方法就是在Views目錄下的web.config文件聲明。
3.4.2 理解ViewBag、ViewData和ViewDataDictionary
從技術角度講,數據從控制器傳送到視圖是通過一個名為ViewData的ViewDataDictionary(這是一個特殊的字典類)。我們可以使用標準的字典語法設置或讀取其中的值,實例如下:
ViewData["CurrentTime"]=DateTime.Now;
ViewBag是ViewData的動態封裝器。這樣我們就可以按照下麵的方式來設置值:ViewBag.CurrentTime=DateTime.Now;
因此,ViewBag.CurrentTime等同於ViewData["CurrentTime"]。
一般來說,我們將遇到的大部分代碼使用ViewBag,而不是ViewData。 大多數情況下,這兩種語法彼此之間並不存在真正的技術差異。ViewBag相對於字典語法而言僅僅是一種受開發人員歡迎、看上去很好看的語法而已。
ViewData和ViewBag
二者很明顯的一個差異就是只有當要訪問的關鍵字是一個有效的C#標識符時,ViewBag才起作用。例如,如果在ViewData["Key With Spaces"]中存放一個值,那麼就不能使用ViewBag訪問。因為這樣根本就無法通過編譯。
另一個需要知道的重要差異就是,動態值不能作為一個參數傳遞給擴展方法。因為C#編譯器為了選擇正確的擴展方法,在編譯時必須知道每一個參數的正確類型。
如果其中任何一個參數是動態的,那麼就不會通過編譯。例如這行代碼就會編譯失敗:
@Html.TextBox("name",ViewBag.Name).要使這行代碼通過編譯有兩種方法:第一是使用ViewData["Name"]。第二種是把ViewData["Name"]值轉換成一個具體的類型(string)ViewData["Name"]。
如剛纔所述,ViewDataDictionary是一個特殊的字典類,而並不只是一個通用的Dictionary。原因之一在於,它有一個額外的Model屬性,允許向視圖提供一個具體的模型對象。因為ViewData中只能有一個模型對象,所以使用ViewDataDictionary向視圖傳遞具體的類十分方便。這樣一來,視圖就可以指定他希望哪個類作為模型對象,從而讓我們能夠利用強類型。
3.5 視圖模型
視圖通常需要顯示各種沒有直接映射到域模型的數據。
把與視圖主模型無關的數據存放在ViewBag屬性中,可以很容易地實現這些數據在視圖中的顯示。當具有一個清晰定義的模型和一些額外的引用數據時,這種方法尤為有用。這種技術的一種常見的應用是使用ViewBag為下拉列表提供表單選項。例如,MVC Music Store項目的Album Edit視圖需要填充Genres和Albums下拉列表,但是這些列表不適合放到Albums模型中。為了應對這些情況,同時不適用無關信息影響Album模型,我們可以將Genre和Album的信息保存到ViewBag中。如下所示:
這麼做當然能夠完成要求,並且也為在視圖中顯示數據提供了一種靈活的方法。但是這並不是一種應該經常使用的方法。一般應該堅持使用強類型模型對象————必須使所有數據都是強類型數據,以便視圖編寫人員能夠利用智能感知功能。
3.6 添加視圖
如何創建視圖呢?可以手動創建視圖文件,然後把它添加在Views目錄下。
顯示添加視圖對話框最簡單的方法就是在操作方法上右擊。
3.7 Razor視圖引擎
3.7.1 Razor的概念
Razor視圖引擎是ASP.NET MVC3中新擴展的內容,並且也是它的預設視圖引擎。
Razor通過理解標記的結構來實現代碼和標記之間儘可能順暢的轉換。
不要過多地考慮
Razor的設計理念是簡單直觀。對於大多數應用,我們不必關心Razor語法----只需要在插入代碼時,輸入HTML和@符號。
3.7.2 代碼表達式
Razor中的核心轉換字元是“@”字元。這個單一字元用作標記-代碼的轉換字元,有時也反過來用作代碼-標記的轉換字元。
3.7.3 HTML編碼
Razor表達式是用HTML自動編碼的。
理解HTML和JavaScript編碼的安全隱患是很重要的。不正確的編碼會使網站和用戶處在危險境地。
3.7.4 代碼塊
Razor在視圖中除了支持代碼表達式以外,還支持代碼塊。
代碼塊除了需要@符號分割之外還需要使用花括弧。
3.7.5 Razor語法實例
1.隱式代碼表達式
<span>@model.Message</span>
Razor中的隱式代碼表達式總是採用HTML編碼方式。
2.顯示代碼表達式
代碼表達式的值被計算並寫入到響應中,這就是在視圖中顯示值的一般原理。
1 <span>1+2=@(1+2)</span>
3.無編碼代碼表達式
有些情況下,需要顯示地渲染一些不應該採用HTML編碼的值,這是可以採用Html.Raw方法來保證該值不被編碼。
<span>@Html.Raw(model.Message)</span>
4.代碼塊
不像代碼表達式先求得表達式的值,然後再輸出到響應,代碼塊是簡單地執行代碼部分。
1 @{ 2 int x=123; 3 string y="because."; 4 }
5.文本和標記相結合
這個例子顯示了Razor中混用文本和標記的概念:
1 @foreach(var item in items) 2 { 3 <span>Item @item.Name</span> 4 }
6.混合代碼和純文本
Razor查找的標簽的開始位置以確定何時將代碼轉換為標記。然而,有時可能想在一個代碼塊之後立即輸出純文本。例如,在下麵的這個例子中就是展示如何在一個條件語句塊中顯示純文本。
1 @if(showMessage){ 2 <text>This is plain text.</text> 3 }
或
1 @if(showMessage){ 2 @:This is plain text. 3 }
7.轉義代碼分隔符
用"@@"來編碼"@"以達到顯示"@"的目的。
8.伺服器端的註釋
@**@
9.調用泛型方法
調用泛型方法的代碼包括尖括弧。
@(Html.SomeMethod<AType>())
3.7.5 佈局
Razor的佈局有助於使應用程式中的多個視圖保持一致的外觀。
3.7.6 ViewStart
每一個視圖都是使用Layout屬性來指定它的佈局。如果多個視圖使用同一個佈局,就會產生冗餘,並且很難維護。
_ViewStart.cshtml頁面可用來消除這種冗餘。這個文件中的代碼鹹魚同目錄下任何視圖代碼的執行。這個文件也可以遞歸的應用到子目錄下的任何視圖。
當創建一個預設的ASP.NET MVC項目時,你將會註意到在Views目錄下會自動添加一個_ViewStart.cshtml文件,它指定了一個預設佈局。
1 @{ 2 Layout="~/Views/Shared/_Layout.cshtml"; 3 }
因為這個代碼優先於任何視圖運行,所以一個視圖可以重寫Layout屬性的預設值,從而重新選擇一個不同的佈局。如果一組視圖擁有共同的設置,那麼_ViewStart.cshtml文件就有了用武之地,因為我們可以在它裡面對共同的視圖配置進行統一設置。如果有視圖需要覆蓋統一的設置,我們只需要修改對應的屬性值即可。