在ASP.NET MVC的一個開源項目MvcContrib中,為我們提供了幾個視圖引擎,例如NVelocity, Brail, NHaml, XSLT。那麼如果我們想在ASP.Net MVC中實現我們自己的一個視圖引擎,我們應該要怎麼做呢?
我們知道呈現視圖是在Controller中通過傳遞視圖名和數據到RenderVIEw()方法來實現的。好,我們就從這裡下手。我們查看一下ASP.Net MVC的源代碼,看看RenderVIEw()這個方法是如何實現的:
protected virtual void RenderView(string viewName, string masterName, object viewData) { ViewContext viewContext = new ViewContext( ControllerContext, viewName, masterName, viewData, TempData); ViewEngine.RenderView(vIEwContext); }//
這是P2的源碼,P3略有不同,原理差不多,從上面的代碼我們可以看到,Controller中的RenderView()方法主要是將ControllerContext, viewName, masterName, viewData, TempData這一堆東西封裝成ViewContext,然後把ViewContext傳遞給ViewEngine.RenderView(viewContext)。嗯,沒錯,我們這裡要實現的就是ViewEngine的RenderVIEw()方法。
ASP.NET MVC為我們提供了一個默認的視圖引擎,這個視圖引擎叫做:WebFormsVIEwEngine. 從名字就可以看出,這個視圖引擎是使用ASP.Net web forms來呈現的。在這裡,我們要實現的視圖引擎所使用的模板用Html文件吧,簡單的模板示例代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html XMLns=""http://www.w3.org/1999/xhtml""> http://www.w3.org/1999/xHtml" > <head> <title>自定義視圖引擎示例</title> </head> <body> <h1>{$ViewData.Title}</h1> <p>{$ViewData.Message}</p> <p>The following fruit is part of a string array: {$ViewData.FruitStrings[1]}</p> <p>The following fruit is part of an object array: {$VIEwData.FruitObjects[1].Name}</p> <p>Here's an undefined variable: {$UNDEFINED}</p> </body> < ml>
下面馬上開始我們的實現。首先,毫無疑問的,我們要創建一個ViewEngine,就命名為 SimpleViewEngine 吧,注意哦,ViewEngine要實現IVIEwEngine接口:
public class SimpleViewEngine : IViewEngine { #region Private members IViewLocator _viewLocator = null; #endregion #region IViewEngine Members : RenderView() public void RenderView(ViewContext viewContext) { string viewLocation = ViewLocator.GetViewLocation (viewContext, viewContext.ViewName); if (string.IsNullOrEmpty(viewLocation)) { throw new InvalidOperationException(string.Format ("View {0} could not be found.", viewContext.ViewName)); } string viewPath = viewContext.HttpContext.Request.MapPath(viewLocation); string viewTemplate = File.ReadAllText(viewPath); //以下為模板解析 IRenderer renderer = new PrintRenderer(); viewTemplate = renderer.Render(viewTemplate, viewContext); viewContext.HttpContext.Response.Write(viewTemplate); } #endregion #region Public properties : ViewLocator public IViewLocator ViewLocator { get { if (this._viewLocator == null) { this._viewLocator = new SimpleViewLocator(); } return this._viewLocator; } set { this._vIEwLocator = value; } } #endregion }
在這裡實現了IViewEngine接口提供的RenderView()方法,這裡要提供一個ViewLocator的屬性。ViewLocator的主要就是根據控制器中傳來的視圖名,進行視圖的定位。在RenderVIEw()方法中首先獲取視圖的路徑,然後把視圖模板讀進來,最後進行模板的解析然後輸出。
我們再來看一下ViewLocator是如何實現的。他是IViewLocator類型的,也就是說SimpleViewLocator實現了IViewLocator接口。SimpleVIEwLocator的實現代碼如下:
public class SimpleViewLocator : ViewLocator { public SimpleViewLocator() { base.ViewLocationFormats = new string[] { "~ iews/{1}/{0}.htm", "~ iews/{1}/{0}.html", "~ iews d/{0}.htm", "~ IEws d/{0}.Html" }; base.MasterLocationFormats = new string[] { "" }; } }
我們的SimpleVIEwLocator 是繼承自ASP.Net MVC的ViewLocator類,而ViewLocator則是實現了IViewLocator接口的。由於ViewLocator已經為了完成了全部的工作,這裡我們只需修改下他的VIEwLocationFormats 來使用我們自己的模板文件就可以了。
我們再來看一下類圖,那就更加清楚了:
注:關於模板解析的部分代碼這裡就不說了,不在討論范圍內,可以自己下載代碼來看。
現在我們基本完成了我們的視圖引擎,那麼如何讓ASP.Net MVC不要使用默認的web forms視圖引擎,而使用我們自定義的視圖引擎呢?
在ASP.Net MVC中,所有的請求都是通過一個工廠類來創建Controller實例的,這個工廠類必須實現IControllerFactory 接口。默認的實現該接口的工廠類是DefaultControllerFactory。這個工廠類就是我們修改默認的視圖引擎為我們的視圖引擎的入口點。為了方便,我們創建一個繼承自DefaultControllerFactory的SimpleControllerFactory :
public class SimpleControllerFactory : DefaultControllerFactory { protected override IController CreateController(RequestContext requestContext, string controllerName) { Controller controller = (Controller)base.CreateController (requestContext, controllerName); controller.ViewEngine = new SimpleVIEwEngine(); //修改默認的視圖引擎為我們剛才創建的視圖引擎 return controller; } }
這裡只要修改controller.ViewEngine為我們自定義的VIEwEngine就可以了.最終的類圖大概如下:
要使我們創建的控制器工廠類SimpleControllerFactory 成為默認的控制器工廠類,我們必須在Global.asax.cs中的Application_Start 事件中添加如下代碼:ControllerBuilder.Current.SetControllerFactory(typeof(SimpleControllerFactory));
到這裡,我們已經完成了我們自己的視圖引擎。
在ASP.Net MVC中實現自定義的視圖引擎是很簡單的,難點在於模板的解析,具體大家可以研究MvcContrib中的四個視圖引擎的代碼。最近要對模板引擎進行研究,大家有什麼其他優秀的、成熟的、開源的模板引擎,麻煩給小弟推薦一下,先謝了。