ASP.NET MVC的Razor引擎:RazorView2012-09-07 博客园 ArtechRazor引擎具有两个核心的类型,一个是表示View本身的类型RazorView,另一个则是获取和创建它的RazorViewEngine,我们将用两篇文章对它们分别进行剖析。Razor引擎下的View通过类型RazorView表示,它与表示Web Form引擎View的类型WebFormView都是BuildManagerCompiledView的子类。一、BuildManagerCompiledView为了能够清楚地说明实现在BuildManagerCompiledView中的View激活与呈现机制,我们列出了BuildManagerCompiledView中与此相关的内部和受保护的成员。
 1: public abstract class BuildManagerCompiledView : IView
 2: {
 3: internal IViewPageActivator ViewPageActivator;
 4:
 5: protected BuildManagerCompiledView(ControllerContext controllerContext, string viewPath);
 6: protected BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator);
 7: internal BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator, IDependencyResolver dependencyResolver);
 8:
 9: public void Render(ViewContext viewContext, TextWriter writer);
10: protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance);
11:
12: internal IBuildManager BuildManager { get; set; }
13: public stringViewPath { get; protected set; }
14: }
通过《View编译原理》的介绍我们知道采用Razor引擎的View文件(.cshtml或者.vbhtml)最终都会编译成一个WebViewPage类型,所以通过RazorView/WebFormView体现的View的呈现机制最终体现在对WebViewPage对象的激活。我们可以利用BuildManager根据View文件的虚拟路径得到编译后的类型。从名称也可以看出来,BuildManagerCompiledView内部就是利用了BuildManager根据指定的View文件虚拟路径完成对WebViewPage对象激活。BuildManagerCompiledView的属性ViewPath表示的就是View文件的虚拟路径,该属性在构造函数中被初始化。BuildManagerCompiledView具有三个构造函数,对象本身的构造逻辑体现在内部构造函数上。如上面的代码片断所示,除了将当前ControllerContext和View文件虚拟路径作为构造函数的参数之外,该构造函数还具有额外两个参数,其类型分别是IViewPageActivator和IDependencyResolver。
 1: public interface IViewPageActivator
 2: {
 3: object Create(ControllerContext controllerContext, Type type);
 4: }
上面的代码片断体现了接口IViewPageActivator的定义。顾名思义,该接口旨在实现对WebViewPage对象的激活,基于类型的对象激活机制实现在Create方法中。BuildManagerCompiledView的构造函数中指定的ViewPageActivator被用于初始化内部字段ViewPageActivator,如果没有通过构造函数显式指定ViewPageActivator对象,默认采用的是一个DefaultViewPageActivator对象。DefaultViewPageActivator是一个具有如下定义的内部类型,我们可以看到它实际上依赖于一个DependencyResolver对象完成针对WebViewPage对象的激活。这个DependencyResolver对象可以通过构造函数进行显式设置,而默认使用的DependencyResolver对象来源于DependencyResolver类型的静态属性Current。
 1: internal class DefaultViewPageActivator : IViewPageActivator
 2: {
 3: private Func<IDependencyResolver> _resolverThunk;
 4: public DefaultViewPageActivator() : this(null)
 5: {}
 6: 
 7: public DefaultViewPageActivator(IDependencyResolver resolver)
 8: {
 9: Func<IDependencyResolver> func = null;
10: if (resolver == null)
11: {
12: this._resolverThunk = () => DependencyResolver.Current;
13: }
14: else
15: {
16: if (func == null)
17: {
18: func = () => resolver;
19: }
20: this._resolverThunk = func;
21: }
22: }
23: 
24: public object Create(ControllerContext controllerContext, Type type)
25: {
26: return (this._resolverThunk().GetService(type) ?? Activator.CreateInstance(type));
27: }
28: }