服務(wù)熱線(xiàn)
153 8323 9821
本文講解ViewEngine的作用, 并且深入解析了實(shí)現(xiàn)ViewEngine相關(guān)的所有接口和類(lèi), 最后演示了如何開(kāi)發(fā)一個(gè)自定義的ViewEngine. 本系列文章已經(jīng)全部更新為ASP.NET MVC 1.0版本.希望大家多多支持!
首先注意: 我會(huì)將大家在MVC之前一直使用的ASP.NET頁(yè)面編程模型稱(chēng)作ASP.NET WebForm編程模型.
上一講中我們已經(jīng)學(xué)習(xí)了如何向View傳遞Model, 以及如何在View中使用Model對(duì)象. 目前為止我們使用的都還是ASP.NET WebForm的頁(yè)面模型,比如aspx頁(yè)面,用戶(hù)控件,母版頁(yè)等. 最后這些頁(yè)面中都要轉(zhuǎn)換為HTML代碼. 比如頁(yè)面中的內(nèi)嵌代碼:
<% = ViewData["model"] %>
你是否思考過(guò), 為何頁(yè)面會(huì)支持<% %>這種語(yǔ)法? 為何最后一個(gè)aspx頁(yè)面會(huì)在瀏覽器中以HTML代碼的形式展現(xiàn)?
有人會(huì)回答這是ASP.NET自帶的語(yǔ)法和功能. 沒(méi)有錯(cuò), ASP.NET幫我們做了編譯頁(yè)面, 輸出HTML, 返回HTML給客戶(hù)端瀏覽器等一系列工作.但是這些工作在MVC框架中有很多是屬于View角色的職責(zé). 為了繼續(xù)使用原有的ASP.NET WebForm頁(yè)面引擎, ASP.NET MVC抽象出來(lái)了ViewEngine這個(gè)角色. 顧名思義ViewEngine即視圖引擎, 其主要作用就是找到View對(duì)象, 編譯View對(duì)象中的語(yǔ)言代碼(執(zhí)行語(yǔ)言邏輯), 并且輸出HTML. 下面講解的WebFormViewEngine就是使用ASP.NET WebForm的頁(yè)面編譯/呈現(xiàn)功能實(shí)現(xiàn)的.
下面將講解和ViewEngine有關(guān)的各個(gè)接口和類(lèi).
IView接口是對(duì)MVC結(jié)構(gòu)中View對(duì)象的抽象, 此接口只有一個(gè)方法:
void Render(ViewContext viewContext, TextWriter writer);
Render方法的作用就是展示View對(duì)象, 通常是將頁(yè)面HTML寫(xiě)入到Writer中供瀏覽器展示.
在本系列第三篇文章中我曾經(jīng)分析過(guò), 雖然IView對(duì)象是MVC中View角色的抽象, 并且提供了Render方法, 但是實(shí)際上真正的View角色的顯示邏輯在ViewPage/ViewUserControl類(lèi)中. 這是由于ASP.NET MVC提供的WebFormViewEngine視圖引擎是使用原有的ASP.NET Web From的頁(yè)面顯示機(jī)制, 我們無(wú)法直接將WebForm模型中的頁(yè)面轉(zhuǎn)化為IView對(duì)象.
于是最后使用了一個(gè)折中的辦法:
在IView對(duì)象的Render方法中調(diào)用WebForm頁(yè)面的Render方法. WebFormView是目前ASP.NET MVC中唯一實(shí)現(xiàn)了IView接口的類(lèi)
所以如果我們使用自定義的ViewEngine引擎, 就可以直接創(chuàng)建一個(gè)實(shí)現(xiàn)了IView接口的類(lèi)實(shí)現(xiàn)Render方法.
ViewEngine即視圖引擎, 在ASP.NET MVC中將ViewEngine的作用抽象成了 IViewEngine 接口.
雖然IViewEngine的職責(zé)是尋找View對(duì)象, 但是其定義的兩個(gè)方法:
返回的結(jié)果是ViewEngineResult對(duì)象, 并不是View對(duì)象. 我們可以將ViewEngineResult理解為一次查詢(xún)的結(jié)果, 在ViewEngineResult對(duì)象中包含有本次找到的IView對(duì)象.
ASP.NET MVC 提供了下面兩個(gè)實(shí)現(xiàn)了IViewEngine接口的類(lèi):
WebFormViewEngine是VirtualPathProviderViewEngine的派生類(lèi).
VirtualPathProviderViewEngine類(lèi)實(shí)現(xiàn)了FindPartialView/FindView方法, 更夠根據(jù)指定的路徑格式搜索頁(yè)面文件, 并且使用了提供了Cache機(jī)制緩存數(shù)據(jù). 注意因?yàn)槭褂玫氖茿SP.NET Cache,依賴(lài)HttpContext對(duì)象, 這就導(dǎo)致Cache無(wú)法在WebService或者WCf等項(xiàng)目中使用. VirtualPathProviderViewEngine尋找頁(yè)面的方法依賴(lài)下面三個(gè)屬性:
在VirtualPathProviderViewEngine中只定義了這三個(gè)屬性, 具體的值在派生類(lèi)WebFormViewEngine中指定:
public WebFormViewEngine() {
MasterLocationFormats = new[] {
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master"
};
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx"
};
PartialViewLocationFormats = ViewLocationFormats;
}
上面的代碼中我們可以一步了然ViewEngine都搜索哪些路徑.甚至還可以添加我們自己的路徑和文件類(lèi)型.
因?yàn)橛辛薞irtualPathProviderViewEngine類(lèi), 在開(kāi)發(fā)自定義的ViewEngine時(shí)不需要再編寫(xiě)搜索View文件的邏輯了.只需要定義搜索路徑即可. 如果不使用ASP.NET WebForm的頁(yè)面顯示方式, 就需要自己定義的View對(duì)象如何顯最后轉(zhuǎn)化為HTML代碼.
在后面的實(shí)例中會(huì)演示創(chuàng)建一個(gè)我們自定義的ViewEngine.
ViewEngineResult是ViewEngine尋找View的查詢(xún)結(jié)果.ViewEngineResult類(lèi)沒(méi)有派生類(lèi), 也就是說(shuō)不同的ViewEngine返回的結(jié)果都是ViewEngineResult對(duì)象.
ViewEngineResult類(lèi)有一個(gè)很重要的構(gòu)造函數(shù):
public ViewEngineResult(IView view, IViewEngine viewEngine)
以WebFormViewEngine為例, 在WebFormViewEngine類(lèi)中定義了 MasterLocationFormats/ViewLocationFormats /PartialViewLocationFormats , 在調(diào)用FindPartialView/FindView方法時(shí), 首先找到View對(duì)象的磁盤(pán)路徑, 然后使用CreatePartialView/CreateView方法將磁盤(pán)路徑轉(zhuǎn)化實(shí)現(xiàn)了IView接口的WebFormView對(duì)象.
WebFormView中依然保存這頁(yè)面對(duì)象的磁盤(pán)路徑, 在調(diào)用Render時(shí)會(huì)根據(jù)磁盤(pán)路徑創(chuàng)建ViewPage對(duì)象, 調(diào)用頁(yè)面的Render方法.ASP.NET MVC編譯頁(yè)面時(shí), 使用了.NET Framework 2.0以上的版本中提供的根據(jù)虛擬路徑編譯頁(yè)面的函數(shù):
BuildManager.CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType)
命名空間為System.Web.Compilation.
ViewEngineCollection是IViewEngine對(duì)象的集合類(lèi). 在我們的系統(tǒng)中可以使用多個(gè)ViewEngine, 在尋找時(shí)會(huì)返回第一個(gè)匹配的ViewEngineResult, 下面是ViewEngineCollection類(lèi)的Find