Razor视图引擎学习
RazorView:
RazorView和WebFormView都是继承自:BuildManageCompiledView。RazorView和WebFormView都有其各自对应的一个引擎:RazorViewEngine和WebFormViewEngine,今天咱们不讲WebFormView,主讲RazorView,我们来看看RazorView类型。在Razor引擎下,通过这一类型来表示View。
1 public class RazorView : BuildManagerCompiledView 2 { 3 // Methods 4 public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions); 5 public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator); 6 protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance); 7 8 // Properties 9 internal DisplayModeProvider DisplayModeProvider { get; set; } 10 public string LayoutPath { get; private set; } 11 public bool RunViewStartPages { get; private set; } 12 internal StartPageLookupDelegate StartPageLookup { get; set; } 13 public IEnumerable<string> ViewStartFileExtensions { get; private set; } 14 internal IVirtualPathFactory VirtualPathFactory { get; set; } 15 }
RenderView方法重写了基类BuildManagerCompiledView的方法。 属性LayoutPath表示布局文件的虚拟路径,而RunViewStartPages则表示是否运行ViewSatrt视图
,ViewStartFileExtensions属性则表示的是ViewStart文件的后缀。例如:“cshtml”、"vbhtml"。我们再来看看其内部的一个很重要的方法:RenderView.
1 protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance) 2 { 3 if (writer == null) 4 { 5 throw new ArgumentNullException("writer"); 6 } 7 WebViewPage page = instance as WebViewPage; 8 if (page == null) 9 { 10 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_WrongViewBase, new object[] { base.ViewPath })); 11 } 12 page.OverridenLayoutPath = this.LayoutPath; 13 page.VirtualPath = base.ViewPath; 14 page.ViewContext = viewContext; 15 page.ViewData = viewContext.ViewData; 16 page.InitHelpers(); 17 if (this.VirtualPathFactory != null) 18 { 19 page.VirtualPathFactory = this.VirtualPathFactory; 20 } 21 if (this.DisplayModeProvider != null) 22 { 23 page.DisplayModeProvider = this.DisplayModeProvider; 24 } 25 WebPageRenderingBase startPage = null; 26 if (this.RunViewStartPages) 27 { 28 startPage = this.StartPageLookup(page, RazorViewEngine.ViewStartFileName, this.ViewStartFileExtensions); 29 } 30 HttpContextBase httpContext = viewContext.HttpContext; 31 WebPageRenderingBase base4 = null; 32 object model = null; 33 page.ExecutePageHierarchy(new WebPageContext(httpContext, base4, model), writer, startPage); 34 }
在此方法中,首先是将传过来的object对象转换为一个WebViewPage对象,接着设置WebViewPage对象的page的布局文件路径,视图文件路径,以及ViewContext和ViewData属性。接着执行初始化,对WebViewPage内部的一些属性进行设置,接着判断执行ViewStart页面的情况,得到表示开启页面的WebPageRenderingBase对象。最后执行page对象的ExecutePageHierarchy方法, 运行执行管道的页层次结构。
来瞧瞧其基类:BuilderManagerCompiledView
1 public abstract class BuildManagerCompiledView : IView 2 { // Methods11 internal BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator, IDependencyResolver dependencyResolver); 12 public void Render(ViewContext viewContext, TextWriter writer); 13 protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance); 14 15 // Properties 16 internal IBuildManager BuildManager { get; set; } 17 public string ViewPath { get; protected set; } 18 }
BuilderManagerCompiledView提供了一个RenderView的抽象方法供子类重写,上面我们已经讲过RenderView方法,可以参考。其中有一个Render方法,我们来看看:
1 public void Render(ViewContext viewContext, TextWriter writer) 2 { 3 if (viewContext == null) 4 { 5 throw new ArgumentNullException("viewContext"); 6 } 7 object instance = null; 8 Type compiledType = this.BuildManager.GetCompiledType(this.ViewPath); 9 if (compiledType != null) 10 { 11 instance = this.ViewPageActivator.Create(this._controllerContext, compiledType); 12 } 13 if (instance == null) 14 { 15 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_ViewCouldNotBeCreated, new object[] { this.ViewPath })); 16 } 17 this.RenderView(viewContext, writer, instance); 18 }
该方法中,首先是根据虚拟路径获得所在View的类型,然在根据类型和控制器上下文创建对象,这个方法最终还是调用了RenderView方法,将instance对象作为参数带入方法中.
可能你对BuildManagerCompiledView构造函数也感兴趣,特别是IViewPageActivator和IDependencyResolver。
1 internal BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator, IDependencyResolver dependencyResolver) 2 { 3 this._controllerContext = controllerContext; 4 this.ViewPath = viewPath; 5 this.ViewPageActivator = viewPageActivator ?? new BuildManagerViewEngine.DefaultViewPageActivator(dependencyResolver); 6 }
看到构造函数结尾对当前ViewPageActivator属性进行赋值的时候,给了一个默认值。看到了吧,当为null的时候,赋了一个DefaultViewPageActivator对象,此时构造函数中传入的参数是dependencyResolver对象。
Razor视图引擎:
1 public class RazorViewEngine : BuildManagerViewEngine 2 { 3 // Fields 4 internal static readonly string ViewStartFileName; 5 6 // Methods 7 static RazorViewEngine(); 8 public RazorViewEngine(); 9 public RazorViewEngine(IViewPageActivator viewPageActivator); 10 protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath); 11 protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath); 12 }
RazorViewEngine继承自BuildManagerViewEngine,内部通过控制器上下文,重写了基类的CreatePartialView创建分布视图方法和CreateView创建视图方法。构造函数设置了视图的搜寻顺序,如果没有提供,则按照这个顺序进行搜寻。