Asp.Net MVC5 视图页面编译调用流转过程,以及页面Web展示

  当控制器调用Action,返回View的时候。

         例如:

    public class HomeController : Controller

    {

        public ActionResult Index()

        {

            return View();

        }

    }

以上是一个最简单的View视图返回调用 

这个return View()运行的结果是直接返回HTMLWeb页面。这个View()是个ViewResult类,如何会返回HTML呢?在CSHTML里面的@符号后面的C#类,变量或者是强类型Model是如何解析的?下面简单的分析下。



View()返回的是ViewResult类的实例,继承自abstract  ViewResultBase, ViewResultBasey又继承自抽象类ActionResult,在ActionResult里面有一个 ExecuteResult抽象方法,参数为控制器上下文.

 

ExecuteResult方法会调用类型为ViewEngineResultFindView方法,传递ControllerContext参数。获取到当前页面IViewIView则调用IView类的抽象Render方法。展开对整个CSHMTL页面的引擎。当当前视图调用Render方法,会导致BuildManagerCompiledViewRazorView两个类的Render方法被调用。最后在RazorViewRenderView方法里面调用 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方法。ExectuePageHierarchyBase.ExectuePageHierarchy.当前页面一般会被编译成WebViewPage的派生类。WebViewPage又派生自WebPageBase。所以Base.ExectuePageHierarchy.会调用webPageBase里面的ExectuePageHierarchy.

 

 

Execute调用的是已经编译好的CSHTML页面。例如控制器为Account,视图Login,那么MVC会把它编译成:名称为_Page_Views_Account_Login_Cshtml的类,这个类继承自WebViewPage<TModel>WebViewPage<TModel>又继承自WebViewPageWebViewPage则继承自WebPageBase


WebPageBase.ExectuePageHierarchy两个参数方法调用了重载的三个参数方法,添加了一个StartPagenull.重复上面的动作,入栈,因为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.

展开阅读全文

没有更多推荐了,返回首页