前文简介:我们抽象类路由规则的对象,RouteBase是路由对象的抽象基类,ASP.NET 的路由系统中有唯一一个从RouteBase继承的路由对象,那就是Route类型了。我们注册了路由对象Route,UrlRoutingModule截获请求,把当前请求的Url地址和RouteTable路由表中注册的路由对象一个一个的比较,如果没有找到就返回Null,请求就到此终止了。如果有匹配的路由对象,选择第一个匹配的Route对象,并且根据该Route对象,生成了路由数据RouteData对象,本对象是为了封装成RequestContext对象,RequestContext对象封装了RouteData和HttpContext对象。

      其实RequestContext对象也是作为参数使用的,我们根据Route对象获得了RouteData,该对象有一个RouteHandler属性,这个属性的值在ASP.NET MVC中是MvcRouteHandler。RouteHandler主要的作用是提供用于处理最终请求的HttpHandler对象,代码如下:

IHttpHandler=RouteData.RouteHandler.GetHttpHandler(requestContext);
HttpContext.Remap(IHttpHandler);

    上文中我们获取到的RequestContext,将此作为参数调用RouteHandler的GetHttpHandler方法,我们获得了IHttpHandler对象,我们需要把请求交给这个HttpHandler来处理,通过HttpContext.Remap(Handler)实现请求的交接,这个Handler在ASP.NET MVC中就是MvcHandler,我们既然获得了HttpHandler对象,也实现了请求的交接,下一步该做什么呢?

一、概览

     我们获得了用于处理请求HttpHandler对象,下一步最重要的任务是把Controller对象找到,RouteData对象的Values属性的Controller键和Action键的值只是一个字符串的结果,我们要通过这个名称找到具体的Controller类型实例,才能执行Action方法,给客户想要的应答。这篇文章就是Controller的激活方法的详解。

      ASP.NET MVC系统真的很庞大,也很复杂,如果我们一上来就瀑布式的说,就像流水账一样,估计也不太容易说明白。为了便于理解,我们人为的把ASP.NET MVC这么庞大的系统拆分成相互独立,又有一定联系的多个子系统,然后我们各个击破,理解起来也就简单了,最后在把各个部分整合在一起,理解就全面了。今天我们要说的这一部分暂时叫做Controller激活系统吧,激活系统有两个含义,一是我们要找到我们需要的Controller对象,并实例化;二是我们药缓存他,并要执行它。

    我们先来看看MvcHandler的源码吧,有助于我们的理解,代码如下:

  1         /// <summary>Selects the controller that will handle an HTTP request.</summary>
  2     public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
  3     {
  4         private struct ProcessRequestState
  5         {
  6             internal IAsyncController AsyncController;
  7 
  8             internal IControllerFactory Factory;
  9 
 10             internal RequestContext RequestContext;
 11 
 12             internal void ReleaseController()
 13             {
 14                 this.Factory.ReleaseController(this.AsyncController);
 15             }
 16         }
 17 
 18         private static readonly object _processRequestTag = new object();
 19 
 20         internal static readonly string MvcVersion = MvcHandler.GetMvcVersionString();
 21 
 22         /// <summary>Contains the header name of the ASP.NET MVC version.</summary>
 23         public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";
 24 
 25         private ControllerBuilder _controllerBuilder;
 26 
 27         internal ControllerBuilder ControllerBuilder
 28         {
 29             get
 30             {
 31                 if (this._controllerBuilder == null)
 32                 {
 33                     this._controllerBuilder = ControllerBuilder.Current;
 34                 }
 35                 return this._controllerBuilder;
 36             }
 37             set
 38             {
 39                 this._controllerBuilder = value;
 40             }
 41         }
 42 
 43         /// <summary>Gets or sets a value that indicates whether the MVC response header is disabled.</summary>
 44         /// <returns>true if the MVC response header is disabled; otherwise, false.</returns>
 45         public static bool DisableMvcResponseHeader
 46         {
 47             get;
 48             set;
 49         }
 50 
 51         /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary>
 52         /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns>
 53         protected virtual bool IsReusable
 54         {
 55             get
 56             {
 57                 return false;
 58             }
 59         }
 60 
 61         /// <summary>Gets the request context.</summary>
 62         /// <returns>The request context.</returns>
 63         public RequestContext RequestContext
 64         {
 65             get;
 66             private set;
 67         }
 68 
 69         /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary>
 70         /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns>
 71         bool IHttpHandler.IsReusable
 72         {
 73             get
 74             {
 75                 return this.IsReusable;
 76             }
 77         }
 78 
 79         /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.MvcHandler" /> class.</summary>
 80         /// <param name="requestContext">The request context.</param>
 81         /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext" /> parameter is null.</exception>
 82         public MvcHandler(RequestContext requestContext)
 83         {
 84             if (requestContext == null)
 85             {
 86                 throw new ArgumentNullException("requestContext");
 87             }
 88             this.RequestContext = requestContext;
 89         }
 90 
 91         /// <summary>Adds the version header by using the specified HTTP context.</summary>
 92         /// <param name="httpContext">The HTTP context.</param>
 93         protected internal virtual void AddVersionHeader(HttpContextBase httpContext)
 94         {
 95             if (!MvcHandler.DisableMvcResponseHeader)
 96             {
 97                 httpContext.Response.AppendHeader(MvcHandler.MvcVersionHeaderName, MvcHandler.MvcVersion);
 98             }
 99         }
100 
101         /// <summary>Called by ASP.NET to begin asynchronous request processing.</summary>
102         /// <returns>The status of the asynchronous call.</returns>
103         /// <param name="httpContext">The HTTP context.</param>
104         /// <param name="callback">The asynchronous callback method.</param>
105         /// <param name="state">The state of the asynchronous object.</param>
106         protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
107         {
108             HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
109             return this.BeginProcessRequest(httpContext2, callback, state);
110         }
111 
112         /// <summary>Called by ASP.NET to begin asynchronous request processing using the base HTTP context.</summary>
113         /// <returns>The status of the asynchronous call.</returns>
114         /// <param name="httpContext">The HTTP context.</param>
115         /// <param name="callback">The asynchronous callback method.</param>
116         /// <param name="state">The state of the asynchronous object.</param>
117         protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
118         {
119             IController controller;
120             IControllerFactory factory;
121             this.ProcessRequestInit(httpContext, out controller, out factory);
122             IAsyncController asyncController = controller as IAsyncController;
123             if (asyncController != null)
124             {
125                 BeginInvokeDelegate<MvcHandler.ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState)
126                 {
127                     IAsyncResult result;
128                     try
129                     {
130                         result = innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState);
131                     }
132                     catch
133                     {
134                         innerState.ReleaseController();
135                         throw;
136                     }
137                     return result;
138                 };
139                 EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState)
140                 {
141                     try
142                     {
143                         innerState.AsyncController.EndExecute(asyncResult);
144                     }
145                     finally
146                     {
147                         innerState.ReleaseController();
148                     }
149                 };
150                 MvcHandler.ProcessRequestState invokeState = new MvcHandler.ProcessRequestState
151                 {
152                     AsyncController = asyncController,
153                     Factory = factory,
154                     RequestContext = this.RequestContext
155                 };
156                 SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext();
157                 return AsyncResultWrapper.Begin<MvcHandler.ProcessRequestState>(callback, state, beginDelegate, endDelegate, invokeState, MvcHandler._processRequestTag, -1, synchronizationContext);
158             }
159             Action action = delegate
160             {
161                 try
162                 {
163                     controller.Execute(this.RequestContext);
164                 }
165                 finally
166                 {
167                     factory.ReleaseController(controller);
168                 }
169             };
170             return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag);
171         }
172 
173         /// <summary>Called by ASP.NET when asynchronous request processing has ended.</summary>
174         /// <param name="asyncResult">The asynchronous result.</param>
175         protected internal virtual void EndProcessRequest(IAsyncResult asyncResult)
176         {
177             AsyncResultWrapper.End(asyncResult, MvcHandler._processRequestTag);
178         }
179 
180         private static string GetMvcVersionString()
181         {
182             return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2);
183         }
184 
185         /// <summary>Processes the request by using the specified HTTP request context.</summary>
186         /// <param name="httpContext">The HTTP context.</param>
187         protected virtual void ProcessRequest(HttpContext httpContext)
188         {
189             HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
190             this.ProcessRequest(httpContext2);
191         }
192 
193         /// <summary>Processes the request by using the specified base HTTP request context.</summary>
194         /// <param name="httpContext">The HTTP context.</param>
195         protected internal virtual void ProcessRequest(HttpContextBase httpContext)
196         {
197             IController controller;
198             IControllerFactory controllerFactory;
199             this.ProcessRequestInit(httpContext, out controller, out controllerFactory);
200             try
201             {
202                 controller.Execute(this.RequestContext);
203             }
204             finally
205             {
206                 controllerFactory.ReleaseController(controller);
207             }
208         }
209 
210         private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
211         {
212             HttpContext current = HttpContext.Current;
213             if (current != null && ValidationUtility.IsValidationEnabled(current) == true)
214             {
215                 ValidationUtility.EnableDynamicValidation(current);
216             }
217             this.AddVersionHeader(httpContext);
218             this.RemoveOptionalRoutingParameters();
219             string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
220             factory = this.ControllerBuilder.GetControllerFactory();
221             controller = factory.CreateController(this.RequestContext, requiredString);
222             if (controller == null)
223             {
224                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[]
225                 {
226                     factory.GetType(),
227                     requiredString
228                 }));
229             }
230         }
231 
232         private void RemoveOptionalRoutingParameters()
233         {
234             RouteValueDictionary values = this.RequestContext.RouteData.Values;
235             values.RemoveFromDictionary((KeyValuePair<string, object> entry) => entry.Value == UrlParameter.Optional);
236         }
237 
238         /// <summary>Enables processing of HTTP Web requests by a custom HTTP handler that implements the <see cref="T:System.Web.IHttpHandler" /> interface.</summary>
239         /// <param name="httpContext">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) that are used to service HTTP requests.</param>
240         void IHttpHandler.ProcessRequest(HttpContext httpContext)
241         {
242             this.ProcessRequest(httpContext);
243         }
244 
245         /// <summary>Called by ASP.NET to begin asynchronous request processing using the base HTTP context.</summary>
246         /// <returns>The status of the asynchronous call.</returns>
247         /// <param name="context">The HTTP context.</param>
248         /// <param name="cb">The asynchronous callback method.</param>
249         /// <param name="extraData">The data.</param>
250         IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
251         {
252             return this.BeginProcessRequest(context, cb, extraData);
253         }
254 
255         /// <summary>Called by ASP.NET when asynchronous request processing has ended.</summary>
256         /// <param name="result">The asynchronous result.</param>
257         void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
258         {
259             this.EndProcessRequest(result);
260         }
261     }
View Code

相关文章: