接触过asp.net mvc的都知道,在传统的webform的模式下,page页面的基类是这样声明的:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage" %>
如果是partial view的话,则是这样声明的:
<%@ Control Language="C#" Inherits="ViewUserControl<dynamic>" %>
可以知道如果传统的view的话是继承于ViewPage这个类,如果是partialView的话则是继承于ViewUserControl这个类。
为了证明我们的分析是否正确,我们看一下asp.net mvc的源码,在源码中有一个WebFormView类,这个就是支持我们传统的web form的基类,我们来看一下它的RenderView是怎么实现的,顺便这里提一下,WebFormView继承于BuildManagerCompiledView,这个我们以后讨论。
protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance){ViewPage viewPage = instance as ViewPage;if (viewPage != null){RenderViewPage(viewContext, viewPage);return;}ViewUserControl viewUserControl = instance as ViewUserControl;if (viewUserControl != null){RenderViewUserControl(viewContext, viewUserControl);return;}throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.WebFormViewEngine_WrongViewBase,ViewPath));}
我们可以清楚的看到,先对object instance判断是否是ViewPage类型,如果为空则判断是否是ViewUserControl类型,如果两者都不是则抛出异常,由此我们可以得知,传统的webform主要由这两个基类组成。在传统的asp.net webform是怎么的情况,还需要大家自己去论证。
好了,我们对asp.net mvc webform进行了分析,以后如果要重写基类的话,只要根据具体的需要对ViewPage和ViewUserControl进行重写就行了。
那么自从asp.net mvc 3.0以后微软推出一个新的视图引擎razor以后,他的基类结构是否发生变化?
事实的确是这样的,当我们使用Razor引擎的时候,我们创建的.cshtml文件没有了之前类似webform的头部声明:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage" %>
取而代之则是什么都没有,这一时让我们需要重写基类的童鞋们摸不着头脑,好了那让我们用同样的思路进行一下分析,razor的头部声明没有,不代表他不继承于基类,既然省略那么说明一个很直接的原因就是他们的view和partialview的头部声明应该是一样的,所以微软干脆就省去不写了。那为了论证我们的猜想是否正确,我们看一下源码。
同样在源码中有一个RazorView类,这个和WebFormView是对应着的,他同样也继承于BuildManagerCompiledView类,同理让我们来看一下他的RenderView方法是如何实现的。
protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance){if (writer == null){throw new ArgumentNullException("writer");}WebViewPage webViewPage = instance as WebViewPage;if (webViewPage == null){throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.CshtmlView_WrongViewBase,ViewPath));}// An overriden master layout might have been specified when the ViewActionResult got returned.// We need to hold on to it so that we can set it on the inner page once it has executed.webViewPage.OverridenLayoutPath = LayoutPath;webViewPage.VirtualPath = ViewPath;webViewPage.ViewContext = viewContext;webViewPage.ViewData = viewContext.ViewData;webViewPage.InitHelpers();if (VirtualPathFactory != null){webViewPage.VirtualPathFactory = VirtualPathFactory;}if (DisplayModeProvider != null){webViewPage.DisplayModeProvider = DisplayModeProvider;}WebPageRenderingBase startPage = null;if (RunViewStartPages){startPage = StartPageLookup(webViewPage, RazorViewEngine.ViewStartFileName, ViewStartFileExtensions);}webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);}
正如我们猜想的在RenderView方法中只看到一个WebViewPage的类,那么就说明Razor引擎的View和PartialView的基类进行了合并,其实我们可以通过扩展名也可以得知,因为razor的扩展名不管是view和partialview都是.cshtml,和之前webform的模式已经不同。
既然razor进行了合并,那么他们的头部声明肯定都是一样的,所以微软就省去了这个环节。
那么razor该如何重写基类呢,如果声明页面头部继承关系呢?
同样我们继承于WebViewPage基类,然后在自己的view或者partialview的头部进行如下声明:
@inherits CustomWebViewPage
或者
@inherits CustomWebViewPage<CustomModel>
这样就可以实现同的自定义实现了,不过这里需要提一点,由于WebViewPage是一个abstract类型的类,所以不能直接实例化,那么一点继承的话,里面必须需要实现一个Excute方法。如果你声明的CustomWebViewPage也是一个abstract类型,则不需要重写,调用默认的实现就可以,但是如果不是则要自己去实现自定义的excute方法。