在 MVC的一个开源项目MvcContrib中
为我们提供了几个视图引擎
例如NVelocity
Brail
NHaml
XSLT
那么如果我们想在ASP
NET MVC中实现我们自己的一个视图引擎
我们应该要怎么做呢?
我们知道呈现视图是在Controller中通过传递视图名和数据到RenderView()方法来实现的好我们就从这里下手我们查看一下ASPNET MVC的源代码看看RenderView()这个方法是如何实现的
protected virtual void RenderView(string viewName string masterName object viewData) { ViewContext viewContext = new ViewContext(ControllerContext viewName masterName viewData TempData); ViewEngineRenderView(viewContext);}//
这是P的源码P略有不同原理差不多从上面的代码我们可以看到Controller中的RenderView()方法主要是将ControllerContext viewName masterName viewData TempData这一堆东西封装成ViewContext然后把ViewContext传递给ViewEngineRenderView(viewContext)嗯没错我们这里要实现的就是ViewEngine的RenderView()方法
ASPNET MVC为我们提供了一个默认的视图引擎这个视图引擎叫做WebFormsViewEngine 从名字就可以看出这个视图引擎是使用ASPNET web forms来呈现的在这里我们要实现的视图引擎所使用的模板用HTML文件吧简单的模板示例代码如下
<!DOCTYPE html PUBLIC //WC//DTD XHTML Transitional//EN transitionaldtd><html XMLns=> ><head> <title>自定义视图引擎示例</title></head><body> <h>{$ViewDataTitle}</h> <p>{$ViewDataMessage}</p> <p>The following fruit is part of a string array: {$ViewDataFruitStrings[]}</p> <p>The following fruit is part of an object array: {$ViewDataFruitObjects[]Name}</p> <p>Heres 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 = ViewLocatorGetViewLocation (viewContext viewContextViewName); if (stringIsNullOrEmpty(viewLocation)) { throw new InvalidOperationException(stringFormat (View {} could not be found viewContextViewName)); } string viewPath = viewContextHttpContextRequestMapPath(viewLocation); string viewTemplate = FileReadAllText(viewPath); //以下为模板解析 IRenderer renderer = new PrintRenderer(); viewTemplate = rendererRender(viewTemplate viewContext); viewContextHttpContextResponseWrite(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() { baseViewLocationFormats = new string[] { ~ iews/{}/{ ~ iews/{}/{l ~ iews d/{ ~ iews d/{l }; baseMasterLocationFormats = new string[] { }; } }
我们的SimpleViewLocator 是继承自 MVC的ViewLocator类
而ViewLocator则是实现了IViewLocator接口的由于ViewLocator已经为了完成了全部的工作这里我们只需修改下他的ViewLocationFormats 来使用我们自己的模板文件就可以了
我们再来看一下类图那就更加清楚了
注关于模板解析的部分代码这里就不说了不在讨论范围内可以自己下载代码来看
现在我们基本完成了我们的视图引擎那么如何让ASPNET MVC不要使用默认的Web forms视图引擎而使用我们自定义的视图引擎呢?
在ASPNET MVC中所有的请求都是通过一个工厂类来创建Controller实例的这个工厂类必须实现IControllerFactory 接口默认的实现该接口的工厂类是DefaultControllerFactory这个工厂类就是我们修改默认的视图引擎为我们的视图引擎的入口点为了方便我们创建一个继承自DefaultControllerFactory的SimpleControllerFactory
public class SimpleControllerFactory : DefaultControllerFactory { protected override IController CreateController(RequestContext requestContext string controllerName) { Controller controller = (Controller)baseCreateController (requestContext controllerName); controllerViewEngine = new SimpleViewEngine(); //修改默认的视图引擎为我们刚才创建的视图引擎 return controller; } }
这里只要修改controllerViewEngine为我们自定义的ViewEngine就可以了最终的类图大概如下
要使我们创建的控制器工厂类SimpleControllerFactory 成为默认的控制器工厂类我们必须在Globalasaxcs中的Application_Start 事件中添加如下代码ControllerBuilderCurrentSetControllerFactory(typeof(SimpleControllerFactory));
到这里我们已经完成了我们自己的视图引擎
在ASPNET MVC中实现自定义的视图引擎是很简单的难点在于模板的解析具体大家可以研究MvcContrib中的四个视图引擎的代码最近要对模板引擎进行研究大家有什么其他优秀的成熟的开源的模板引擎麻烦给小弟推荐一下先谢了