这几天利用空闲时间,我将ASP.NET反编译后的源代码并结合园子里几位大侠的写的文章认真的看了一遍,收获颇丰,同时也摘要了一些学习内容,存入了该篇文章:《ASP.NET运行机制图解》,在对整个ASP.NET的运行机制有所了解后,我又对MVC的运行机制也进行了源码分析,因为网上已经有很多的关于MVC实现原理的介绍,所以我这里不再重复讨论这方面的内容,而主要讲解一下Controller的的创建、执行以及如何实现依赖注入,注入的步骤是什么?
首先,我们来看一下正常的Controller的的创建与执行顺序:
大家都应该知道,用于处理ASP.NET请求是由实现了IHttpHandler的对象来进行处理的,我们所常见的Handler包括但不限于:Page,MvcHandler等
如下是MvcHandler类中的方法及执行步骤说明:
处理入口方法:异步-->BeginProcessRequest,同步--> ProcessRequest,源代码如下:
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { return this.BeginProcessRequest(context, cb, extraData); } void IHttpHandler.ProcessRequest(HttpContext httpContext) { this.ProcessRequest(httpContext); }
注意这两个方法是显示实现IHttpHandler的同名方法的,不能直接调用,必需转换成IHttpHandler类型后才能调用,调用转到如下方法:
protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) { HttpContextBase httpContext2 = new HttpContextWrapper(httpContext); return this.BeginProcessRequest(httpContext2, callback, state); } protected virtual void ProcessRequest(HttpContext httpContext) { HttpContextBase httpContext2 = new HttpContextWrapper(httpContext); this.ProcessRequest(httpContext2); }
当然这两个方法均又分别调动了各自的重载方法,在重载方法中都调用了ProcessRequestInit,源代码如下:
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { if (ValidationUtility.IsValidationEnabled(HttpContext.Current) == true) { ValidationUtility.EnableDynamicValidation(HttpContext.Current); } this.AddVersionHeader(httpContext); this.RemoveOptionalRoutingParameters(); string requiredString = this.RequestContext.RouteData.GetRequiredString("controller"); factory = this.ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(this.RequestContext, requiredString); if (controller == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[] { factory.GetType(), requiredString })); } }
红色标明的就是创建Controller的地方,创建完后就开始执行Controller,异步与同步方法的执行有所不同,源代码如下:
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { return SecurityUtil.ProcessInApplicationTrust<IAsyncResult>(delegate { IController controller; IControllerFactory factory; this.ProcessRequestInit(httpContext, out controller, out factory); IAsyncController asyncController = controller as IAsyncController; if (asyncController != null) { BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) { IAsyncResult result; try { result = asyncController.BeginExecute(this.RequestContext, asyncCallback, asyncState); } catch { factory.ReleaseController(asyncController); throw; } return result; }; EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) { try { asyncController.EndExecute(asyncResult); } finally { factory.ReleaseController(asyncController); } }; SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext(); AsyncCallback callback2 = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, synchronizationContext); return AsyncResultWrapper.Begin(callback2, state, beginDelegate, endDelegate, MvcHandler._processRequestTag); } Action action = delegate { try { controller.Execute(this.RequestContext); } finally { factory.ReleaseController(controller); } }; return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag); }); } protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) { SecurityUtil.ProcessInApplicationTrust(delegate { AsyncResultWrapper.End(asyncResult, MvcHandler._processRequestTag); }); } protected internal virtual void ProcessRequest(HttpContextBase httpContext) { SecurityUtil.ProcessInApplicationTrust(delegate { IController controller; IControllerFactory controllerFactory; this.ProcessRequestInit(httpContext, out controller, out controllerFactory); try { controller.Execute(this.RequestContext); } finally { controllerFactory.ReleaseController(controller); } }); }