例如:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
以上是一个最简单的View视图返回调用
这个return View()运行的结果是直接返回HTML到Web页面。这个View()是个ViewResult类,如何会返回HTML呢?在CSHTML里面的@符号后面的C#类,变量或者是强类型Model是如何解析的?下面简单的分析下。
View()返回的是ViewResult类的实例,继承自abstract ViewResultBase, ViewResultBasey又继承自抽象类ActionResult,在ActionResult里面有一个 ExecuteResult抽象方法,参数为控制器上下文.
ExecuteResult方法会调用类型为ViewEngineResult的FindView方法,传递ControllerContext参数。获取到当前页面IView,IView则调用IView类的抽象Render方法。展开对整个CSHMTL页面的引擎。当当前视图调用Render方法,会导致BuildManagerCompiledView和RazorView两个类的Render方法被调用。最后在RazorView的RenderView方法里面调用 :webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);会调用WebViewPage里面的ExectuePageHierarchy方法,因为webViewPage里面没有三个重载的ExectuePageHierarchy方法,会转到WebViewPage的基类WebPageBase执行它的ExectuePageHierarchy方法。此方法里面有三个动作,入栈(push),运行页面(startpage.Execute),出站(pop).
入栈会把当前httpResonse.Response.Output放在当前Current属性里,把当前环境下的textwriter入栈,作为临时变量。页面运行会跳转到类StartPage里面,StartPage.Execute会调用Execute运行当前的首页或者是母版页或者是布局页面。比如ViewStart.CSHTML.则会被编译成_Page_View_ViewStart.CSHTML.继承自ViewStartPage,当Execute被调用的时候,实际上是调用的_Page_View_ViewStart.CSHTML里面的Execute方法。这个方法是事先被编译好的。在Asp.Net MVC运行期间。可以通过修改MVC根目录下webconfig配置文件的Compilation字段设置运行期间被编译的CSHMTL文件的路径。在Compilation字节添加tempDirectory字段,Value为路径名即可。在Visual Studio2015下面可以通过Reflector 9.0反编译上面路径下被编译程序集。Execute被调用之后,会调用一个RunPage方法。RunPage会获取当前页面然后调用ExectuePageHierarchy方法。ExectuePageHierarchy会Base.ExectuePageHierarchy.当前页面一般会被编译成WebViewPage的派生类。WebViewPage又派生自WebPageBase。所以Base.ExectuePageHierarchy.会调用webPageBase里面的ExectuePageHierarchy.。
Execute调用的是已经编译好的CSHTML页面。例如控制器为Account,视图Login,那么MVC会把它编译成:名称为_Page_Views_Account_Login_Cshtml的类,这个类继承自WebViewPage<TModel>。WebViewPage<TModel>又继承自WebViewPage,WebViewPage则继承自WebPageBase。
WebPageBase.ExectuePageHierarchy两个参数方法调用了重载的三个参数方法,添加了一个StartPage:null.重复上面的动作,入栈,因为StartPage==null,所以会调用WebViewPage.ExectuePageHierarchy. WebViewPage.ExectuePageHierarchy.同样的调用Base.ExectuePageHierarchy.然后再调用Execute把当前页面例如:_Page_Account_Login_Cshtml这种页面的HTML以及脚本,以及C#类语言Model等写入当前流。至此,整个过程完成。Render调用结束。
_Page_Account_Login_Cshtml类的代码如下:
public class _Page_Views_Account_Login_cshtml : WebViewPage<LoginViewModel>
{
// Methods
public _Page_Views_Account_Login_cshtml();
public override void Execute();
// Properties
protected global_asax ApplicationInstance { get; }
// Nested Types
[CompilerGenerated]
private static class <>o__3
{
// Fields
public static CallSite<Func<CallSite, object, string, object>> <>p__0;
public static CallSite<Func<CallSite, object, object>> <>p__1;
public static CallSite<Action<CallSite, _Page_Views_Account_Login_cshtml, object>> <>p__2;
public static CallSite<Func<CallSite, object, object>> <>p__3;
public static CallSite<Func<CallSite, object, object>> <>p__4;
public static CallSite<Func<CallSite, object, string>> <>p__5;
}
}
Expand Methods
在继承自WebStartPage和WebViewPage的编译类中,Execute方法部分代码如下:
public override void Execute()
{
if (<>o__3.<>p__0 == null)
{
CSharpArgumentInfo[] argumentInfo = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) };
<>o__3.<>p__0 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember (CSharpBinderFlags.None, "Title", typeof(_Page_Views_Account_Login_cshtml), argumentInfo));
}
<>o__3.<>p__0.Target(<>o__3.<>p__0, base.get_ViewBag(), "登录");
base.BeginContext("~/Views/Account/Login.cshtml", 0x56, 8, true);
this.WriteLiteral("\r\n\r\n<h2>");
base.EndContext("~/Views/Account/Login.cshtml", 0x56, 8, true);
base.BeginContext("~/Views/Account/Login.cshtml", 0x5f, 13, false);
if (<>o__3.<>p__2 == null)
{
CSharpArgumentInfo[] infoArray2 = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) };
<>o__3.<>p__2 = CallSite<Action<CallSite, _Page_Views_Account_Login_cshtml, object>>.Create (Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded | CSharpBinderFlags.InvokeSimpleName, "Write", null, typeof(_Page_Views_Account_Login_cshtml), infoArray2));
}
if (<>o__3.<>p__1 == null)
{
CSharpArgumentInfo[] infoArray3 = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) };
<>o__3.<>p__1 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember (CSharpBinderFlags.None, "Title", typeof(_Page_Views_Account_Login_cshtml), infoArray3));
}
<>o__3.<>p__2.Target(<>o__3.<>p__2, this, <>o__3.<>p__1.Target(<>o__3.<>p__1, base.get_ViewBag()));
base.EndContext("~/Views/Account/Login.cshtml", 0x5f, 13, false);
base.BeginContext("~/Views/Account/Login.cshtml", 0x6c, 12, true);
this.WriteLiteral("。</h2>\r\n<div");
}
类继承结构:
WebViewPage-》WebPageBase-》WebPageRenderingBase-》WebPageExecutingBase
WebStartPage->StartPage->WebPageRenderingBase->WebPageExecutingBase
视图类继承方法IView-》BuildManagerCompiledView -》RazorView.