最近一段时间接手过的项目都是基于Asp.Net的,以前对aspnet运行机制有一个大概的了解,总觉得不够透彻,按自己的理解来分析一下。

Asp.Net 运行机制

理解mvc运行原理的前提是要了解aspnet运行原理,这方面网上资料多如牛毛,我这里就大致说一下aspnet生命周期

asp.net mvc文件结构 asp.net mvc运行原理_asp.net mvc文件结构

Http请求到IIS后,如果是静态资源则IIS读取后返回客户端,动态请求被isap.dll 转发自net托管平台处理,首先HttpRuntime中创建Application,它是整个请求生命周期的开始,运行在单独的Appdomain中,在Application 中顺序调用所有已注册的Ihttpmodule,在IHttpModule中可以 "短路"(终止后续IHttpModule的执行),很多Web框架都是在这里做了文章,包括大名鼎鼎的Asp.Net Mvc, IHttpModule执行完后 最终请求被交给IHttpHandler, 在Handler中执行完毕后 再一层层返回到客户端。

 

ASP.NET MVC5 运行原理

这是来自微软官方的运行原理图

asp.net mvc文件结构 asp.net mvc运行原理_mvc_02

当前请求到达 IIS服务器后,同样动态请求被转发到net平台,在管道执行过程中(IHttpModule),有一个特殊的IHttpModule

它就是 UrlRoutingModule ,MVC从这里就开始了。

它 根据当前的HttpContext封装HttpContextWrapper,从Route路由表中取出和当前URL匹配的路由数据(RouteData),接着生成RequestContext对象,然后创建IHttpHandler这里是MvcHandler在MvcHandler中完成了图中处理管线的所有操作。

下面从源码级分析一次请求处理流程

当请求到达路由Module时,创建MvcHandler并将封装好的RequestContext请求上下文传递给它

public MvcHandler(RequestContext requestContext)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            RequestContext = requestContext;
        }

执行MvcHandler的BeginProcessRequest方法,创建HttpContextWrapper

protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
        {
            HttpContextBase httpContextBase = new HttpContextWrapper(httpContext);
            return BeginProcessRequest(httpContextBase, callback, state);
        }

在BeginProcess中实例化了Controller并执行对应的Action等,做了很多工作,一步步来分析

protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
        {
            IController controller;
            IControllerFactory factory;
            ProcessRequestInit(httpContext, out controller, out factory);

            IAsyncController asyncController = controller as IAsyncController;
            if (asyncController != null)
            {
                // asynchronous controller

                // Ensure delegates continue to use the C# Compiler static delegate caching optimization.
                BeginInvokeDelegate<ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ProcessRequestState innerState)
                {
                    try
                    {
                        return innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState);
                    }
                    catch
                    {
                        innerState.ReleaseController();
                        throw;
                    }
                };

                EndInvokeVoidDelegate<ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, ProcessRequestState innerState)
                {
                    try
                    {
                        innerState.AsyncController.EndExecute(asyncResult);
                    }
                    finally
                    {
                        innerState.ReleaseController();
                    }
                };
                ProcessRequestState outerState = new ProcessRequestState() 
                {
                    AsyncController = asyncController, Factory = factory, RequestContext = RequestContext
                };
                
                SynchronizationContext callbackSyncContext = SynchronizationContextUtil.GetSynchronizationContext();
                return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, outerState, _processRequestTag, callbackSyncContext: callbackSyncContext);
            }
            else
            {
                // synchronous controller
                Action action = delegate
                {
                    try
                    {
                        controller.Execute(RequestContext);
                    }
                    finally
                    {
                        factory.ReleaseController(controller);
                    }
                };

                return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
            }
        }

在ProcessRequestInit 中,

首先在http响应报文中添加mvc版本信息

AddVersionHeader(httpContext);

从本次请求的路由数据中得到Controller(控制器)名称

//得到控制器名称
string controllerName = RequestContext.RouteData.GetRequiredString("controller");

//从默认的控制器工厂创建控制器实例
factory = ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(RequestContext, controllerName);
            if (controller == null)
            {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        MvcResources.ControllerBuilder_FactoryReturnedNull,
                        factory.GetType(),
                        controllerName));
            }

实例化后的Controller

asp.net mvc文件结构 asp.net mvc运行原理_实例化_03

在这个实例化的控制器中,可以拿到很多相关的请求对象 Request Respone Model 等等,

接着如果Controller是异步则异步执行BeginExecute,否则直接执行Execute

Execute方法中执行注册的过滤器(Filter),然后通过反射调用我们的Action,执行完后返回IActionResult,这个IActionResult就是返回给客户端数据包装对象(可能不太贴切)。

处理完成后会执行factory.ReleaseController(controller); 以释放Controller

至此一次http请求在mvc中处理完毕。