Net我爱编程程序员

Web流程-MVC执行

2018-04-14  本文已影响82人  Aneko

上一篇了解了 ISAPI执行原理,现在我们接着看 请求在MVC中是怎么处理的;

在了解MVC流程之前,我们先来了解一下一个重要的MvcHandler 类型,他是由路由生成的;

一. 路由模块

路由模块存在于 System.Web.Routing.dll 类库中,其中有一个重要的类 UrlRoutingModule;

  1. 网站配置主要分两种,全局和本站的Web.config配置;
    1.1. 全局配置目录D:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config
<httpModules>
         .......
           <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
           .......
</httpModules>

1.2. 本站配置存在,应用程序的根目录下;

  1. 当请求管道接收到请求时,就会加载UrlRoutingModule,我们看内部怎么处理。我们看到在第七个管道事件PostResolveRequestCache中注册了一个事件;
 public class UrlRoutingModule : IHttpModule
    {
       
        protected virtual void Init(HttpApplication application)
        {
            if (application.Context.Items[_contextKey] == null)
            {
                application.Context.Items[_contextKey] = _contextKey;
                //第七个管道事件
                application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
            }
        }
        
        private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication) sender;
            HttpContextBase context = new HttpContextWrapper(application.Context);
            this.PostResolveRequestCache(context);
        }

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
//在RouteCollection中封装了所有的路由信息
            RouteData routeData = this.RouteCollection.GetRouteData(context);
            if (routeData != null)
            {
                // IRouteHandler 拿到具体的handle
                IRouteHandler routeHandler = routeData.RouteHandler;
                if (routeHandler == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, System.Web.SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
                }
                if (!(routeHandler is StopRoutingHandler))
                {
                    RequestContext requestContext = new RequestContext(context, routeData);
                    context.Request.RequestContext = requestContext;
                    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
                    if (httpHandler == null)
                    {
                        throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
                    }
                    if (httpHandler is UrlAuthFailureHandler)
                    {
                        if (!FormsAuthenticationModule.FormsAuthRequired)
                        {
                            throw new HttpException(0x191, System.Web.SR.GetString("Assess_Denied_Description3"));
                        }
                        UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
                    }
                    else
                    {
                        context.RemapHandler(httpHandler);
                    }
                }
            }
        }
......

2.1. 在Application_Strat方法 路由注册中通过方法MapRoute将请求的地址写入RouteCollection中。

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
   ......
    Route item = new Route(url, new MvcRouteHandler()) {
        Defaults = CreateRouteValueDictionary(defaults),
        Constraints = CreateRouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    };
    if ((namespaces != null) && (namespaces.Length > 0))
    {
        item.DataTokens["Namespaces"] = namespaces;
    }
    routes.Add(name, item);
    return item;
}

2.2. 通过方法 routeHandler.GetHttpHandler(requestContext) 实例MvcHandler的生成

  protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
            return new MvcHandler(requestContext);
        }

二.从MvcHandler的PR方法进入MVC流程的执行

一.Controller创建流程

以上介绍了MvcHandler在第七个事件中生成,在第11和12个事件之中调用PR方法开始响应请求,以下介绍PR中到底执行了什么;

  1. 通过ProcessRequestInit内部的工厂方法this.ControllerBuilder.GetControllerFactory().CreateController() 带入上下文对象创建Controller实例
 protected internal virtual void ProcessRequest(HttpContextBase httpContext)
        {
            IController controller;
            IControllerFactory factory;
            this.ProcessRequestInit(httpContext, out controller, out factory);
            try
            {
                controller.Execute(this.RequestContext);
            }
            finally
            {
                factory.ReleaseController(controller);
            }
        }

 private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
        {
            HttpContext current = HttpContext.Current;
            ......
            factory = this.ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(this.RequestContext, requiredString);
           ......
        }
  1. 调用 controller.Execute(this.RequestContext)执行具体的Action; 通过ControllerBase的ExecuteCore 方法执行
  public abstract class ControllerBase : IController
    {
        ......
        protected virtual void Execute(RequestContext requestContext)
        {
            ......
            using (ScopeStorage.CreateTransientScope())
            {
                this.ExecuteCore();
            }
            ......
        }

3.调用Controller的ExecuteCore().GetRequiredString()方法;获取Action方法名称,并通过ExecuteCore().InvokeAction()触发.
3.1. 可以看到在InvokeAction.FindAction()方法中根据上下文,方法名 寻找对应的描述或特性;
3.2. 可以看到在InvokeAction.GetFilters()方法中加载过滤器

public abstract class Controller
{
protected override void ExecuteCore()
        {
            this.PossiblyLoadTempData();
            try
            {
                string requiredString = this.RouteData.GetRequiredString("action");
                if (!this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString))
                {
                    this.HandleUnknownAction(requiredString);
                }
            }
            finally
            {
                this.PossiblySaveTempData();
            }
        }

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
        {
            ......
            ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
            ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
            if (actionDescriptor == null)
            {
                return false;
            }
            FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
            try
            {
                AuthorizationContext context = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
          ......

  1. 通过InvokeActionMethodWithFilters方法得到了一个Result对象;我们具体来看先通过actionDescriptor.Execute()生成结果,最后转为 ActionResult对象返回
 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
        {
            ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
            Func<ActionExecutedContext> seed = () 
=> new ActionExecutedContext(controllerContext, actionDescriptor, false, null) 
{ 
Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
 };
            return filters.Reverse<IActionFilter>().Aggregate<IActionFilter, Func<ActionExecutedContext>>(seed, (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next))();
        }

 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
        {
            //此处执行action方法
            object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
            return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
        }

 protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
        {
            ActionResult result;
            if (actionReturnValue == null)
            {
                return new EmptyResult();
            }
            //子类转基类返回
            if (actionReturnValue as ActionResult)
            {
                result = actionReturnValue as ActionResult;
            }
            else
            {
                ContentResult result2 = new ContentResult {
                    Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture)
                };
                result = result2;
            }
            return result;
        }
  1. 继续执行InvokeActionResultWithFilters方法完成Result的 AOP;
 protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult)
        {
            ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult);
            Func<ResultExecutedContext> seed = delegate {
                this.InvokeActionResult(controllerContext, actionResult);
                return new ResultExecutedContext(controllerContext, actionResult, false, null);
            };
            return filters.Reverse<IResultFilter>().Aggregate<IResultFilter, Func<ResultExecutedContext>>(seed, (next, filter) => () => InvokeActionResultFilter(filter, preContext, next))();
        }
二.View创建流程

ActionResult已经拿到,现在要对其进行渲染;我们看一下它内部的渲染方法

  1. 通过ActionResult基类ActionResultBase.ExecuteResult()方法,看到创建一个 ViewEngineResult渲染引擎
 public override void ExecuteResult(ControllerContext context)
        {
                 ......
            if (string.IsNullOrEmpty(this.ViewName))
            {
                this.ViewName = context.RouteData.GetRequiredString("action");
            }
            ViewEngineResult result = null;
            if (this.View == null)
            {
                result = this.FindView(context);
                this.View = result.View;
            }
  1. 通过ViewContext方法加载ViewData,TempData 等等数据生成ViewContext
 public override void ExecuteResult(ControllerContext context)
        {
          ......
            TextWriter output = context.HttpContext.Response.Output;
            ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
            this.View.Render(viewContext, output);
          ......
}


public ViewContext(ControllerContext controllerContext, IView view, ViewDataDictionary viewData, TempDataDictionary tempData, TextWriter writer) : base(controllerContext)
        {
            this._defaultFormContext = new System.Web.Mvc.FormContext();
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (view == null)
            {
                throw new ArgumentNullException("view");
            }
            if (viewData == null)
            {
                throw new ArgumentNullException("viewData");
            }
            if (tempData == null)
            {
                throw new ArgumentNullException("tempData");
            }
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            this.View = view;
            this.ViewData = viewData;
            this.Writer = writer;
            this.TempData = tempData;
        }
  1. 当上下文ViewContext,TextWriter已经准备好就可以渲染View了;我们从View.Render(viewContext, output)方法中看到,根据View类型生成类实例;
 public void Render(ViewContext viewContext, TextWriter writer)
        {
       ......
            Type compiledType = this.BuildManager.GetCompiledType(this.ViewPath);
            if (compiledType != null)
            {
                instance = this.ViewPageActivator.Create(this._controllerContext, compiledType);
            }
      ......
            this.RenderView(viewContext, writer, instance);
        }
  1. 我们看到从RenderView方法中生成WebViewPage 对象,并将返回数据写入对象属性中,最后调用ExecutePageHierarchy渲染;至此整个View渲染流程就结束了;
 protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            WebViewPage page = instance as WebViewPage;
            if (page == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_WrongViewBase, new object[] { base.ViewPath }));
            }
            page.OverridenLayoutPath = this.LayoutPath;
            page.VirtualPath = base.ViewPath;
            page.ViewContext = viewContext;
            page.ViewData = viewContext.ViewData;
            page.InitHelpers();
            if (this.VirtualPathFactory != null)
            {
                page.VirtualPathFactory = this.VirtualPathFactory;
            }
            if (this.DisplayModeProvider != null)
            {
                page.DisplayModeProvider = this.DisplayModeProvider;
            }
            WebPageRenderingBase startPage = null;
            if (this.RunViewStartPages)
            {
                startPage = this.StartPageLookup(page, RazorViewEngine.ViewStartFileName, this.ViewStartFileExtensions);
            }
            HttpContextBase httpContext = viewContext.HttpContext;
            WebPageRenderingBase base4 = null;
            object model = null;
            page.ExecutePageHierarchy(new WebPageContext(httpContext, base4, model), writer, startPage);
        }

参考文档 :
博客园:[http://www.cnblogs.com/edisonchou/p/4226558.html]
博客园:[http://www.cnblogs.com/yinzixin/archive/2012/12/05/2799459.html]

上一篇下一篇

猜你喜欢

热点阅读