带你读开源—ASP.NET_MVC(五)

        书接上文,我们继续跟踪CreateView方法,发现它是一个抽象方法,好吧,我们发现BuildManagerViewEngine继承了VirtualPathProviderViewEngine,但是它并没有重写了CreateView方法,不要慌,我们继续摸索,发现RazorViewEngine和WebFormViewEngine(先不管他)又继承了BuildManagerViewEngine,在这里我们只看RazorViewEngine的CreateView方法重写(代码段1)。

        protected override IViewCreateView(ControllerContext controllerContext, string viewPath, stringmasterPath)
        {
            var view = newRazorView(controllerContext, viewPath,
                                    layoutPath: masterPath, runViewStartPages: true,viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
            {
                DisplayModeProvider =DisplayModeProvider
            };
            return view;
        }


代码段 1

        代码段1得到了一个IView对象,进而使得“带你读开源—ASP.NET_MVC(四)”代码段10得到一个ViewEngineResult,我们再转到“带你读开源—ASP.NET_MVC(四)”代码段2中的语句【result = FindView(context);View = result.View;】,到此我们便得到了一个View对象,进而调用View.Render(viewContext, writer)方法,而其中的writer 又是什么东东?我们找到语句【TextWriter writer =context.HttpContext.Response.Output;】,豁然开朗不?我们久违的、日思夜想的Response终于出现了,有了它,我们就可以把HTML响应渲染回送到浏览器,至此,从浏览器发出HTTP请求,到服务器发回HTML响应,构成完整的回路。我靠,累死我了!

        我们再看代码段2,这是一个IView接口的定义,该接口仅有一个方法Render,用以向浏览器渲染HTML页面。

<pre name="code" class="csharp">    public interface IView
    {
        void Render(ViewContext viewContext, TextWriterwriter);
    }



代码段 2

        只有一个类实现了IView接口,这个类就是BuildManagerCompiledView,我们看Render方法的具体实现,见代码段3。

        

public virtual void Render(ViewContextviewContext, TextWriter writer)
        {
            if (viewContext == null)
            {
                throw newArgumentNullException("viewContext");
            }
 
            object instance = null;
 
            Type type =BuildManager.GetCompiledType(ViewPath);
            if (type != null)
            {
                instance =ViewPageActivator.Create(_controllerContext, type);
            }
 
            if (instance == null)
            {
                throw newInvalidOperationException(
                    String.Format(
                       CultureInfo.CurrentCulture,
                        MvcResources.CshtmlView_ViewCouldNotBeCreated,
                        ViewPath));
            }
 
            RenderView(viewContext, writer,instance);
        }

代码段 3

        代码段3中有两个地方需要我们注意:

        ①【instance= ViewPageActivator.Create(_controllerContext, type);】

        ②【RenderView(viewContext,writer, instance);】

        其中,①是实例化视图类,②是渲染视图。为了突出主线,我们先分析②。我们发现RenderView是一个抽象方法,凭经验BuildManagerCompiledView类应该有子类重写了RenderView方法,在源码中寻找,发现它有两个子类,即WebFormView和RazorView,见到这两个类开心吧?呵呵!我们在这里先只分析RazorView的RenderView方法重写,见代码段4。

    

    protected override voidRenderView(ViewContext viewContext, TextWriter writer, object instance)
        {
            if (writer == null)
            {
                throw newArgumentNullException("writer");
            }
 
            WebViewPage webViewPage = instanceas WebViewPage;
            if (webViewPage == null)
            {
                throw newInvalidOperationException(
                    String.Format(
                       CultureInfo.CurrentCulture,
                        MvcResources.CshtmlView_WrongViewBase,
                        ViewPath));
            }
 
            // An overriden master layout mighthave been specified when the ViewActionResult got returned.
            // We need to hold on to it so thatwe 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);
        }

代码段 4

        在代码段4中找到语句【webViewPage.ExecutePageHierarchy(new WebPageContext(context:viewContext.HttpContext, page: null, model: null), writer, startPage);】,这句是执行渲染的核心语句。继续跟踪进入webViewPage.ExecutePageHierarchy,见代码段5。

  

      // This method is only used byWebPageBase to allow passing in the view context and writer.
        public voidExecutePageHierarchy(WebPageContext pageContext, TextWriter writer,WebPageRenderingBase startPage)
        {
            PushContext(pageContext, writer);
 
            if (startPage != null)
            {
                if (startPage != this)
                {
                    var startPageContext =WebPageContext.CreateNestedPageContext<object>(parentContext:pageContext, pageData: null, model: null, isLayoutPage: false);
                    startPageContext.Page =startPage;
                    startPage.PageContext = startPageContext;
                }
               startPage.ExecutePageHierarchy();
            }
            else
            {
                ExecutePageHierarchy();
            }
            PopContext();
        }

代码段 5

        在代码段5中找到ExecutePageHierarchy方法,进入其定义,见代码段6。

     

  [SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Wereally don't care if SourceHeader fails, and we don't want it to fail any realrequests ever")]
        public override voidExecutePageHierarchy()
        {
            // Unlike InitPages, for a WebPagethere is no hierarchy - it is always
            // the last file to execute in thechain. There can still be layout pages
            // and partial pages, but they arenever part of the hierarchy.
 
            // (add server header for falcondebugging)
            // call to MapPath() is expensive.If we are not emiting source files to header,
            // don't bother to populate theSourceFiles collection. This saves perf significantly.
            if(WebPageHttpHandler.ShouldGenerateSourceHeader(Context))
            {
                try
                {
                    string vp = VirtualPath;
                    if (vp != null)
                    {
                        string path =Context.Request.MapPath(vp);
                        if (!path.IsEmpty())
                        {
                           PageContext.SourceFiles.Add(path);
                        }
                    }
                }
                catch
                {
                    // we really don't care ifthis ever fails, so we swallow all exceptions
                }
            }
 
            TemplateStack.Push(Context, this);
            try
            {
                // Execute thedeveloper-written code of the WebPage
                Execute();
            }
            finally
            {
                TemplateStack.Pop(Context);
            }
        }

代码段 6

        在代码段6中找到语句Execute()方法,在这个方法上方有一条注释“//Execute thedeveloper-written code of the WebPage”,大概意思是“执行开发者编写的页面代码”,明白了吧?这句的功能就是执行你编写的视图代码,即.cshtml文件。那么肯定有人要提出疑问了,.cshtml文件怎么执行?它不是一段html脚本么?不错,.cshtml文件确实是一段html脚本,不能被直接执行,在此留一个悬念[1]

        未完待续。。。

你可能感兴趣的:(mvc,.net,开源,asp.net)