你真的熟悉ASP.NET MVC的整個生命周期嗎?

一、介紹

    我們做開發的,尤其是做微軟技術棧的,有一個方向是跳不過去的,那就是MVC開發。我相信大家,做ASP.NET MVC 開發有的有很長時間,當然,也有剛進入這個行業的。無論如何,如果有人問你,你知道ASP.NET MVC的生命周期嗎?你知道它的來世今生嗎?你知道它和 ASP.NET WEBFORM 有什麼區別嗎?估計,這些問題,有很多人會答不上來,或者說不清楚。今天,我就把我的理解寫出來,也是對我自己學習的一次回顧和總結吧。當然,由於本人能力有限,在寫的過程中也可能會有一些錯誤,希望大家多多包涵,當然,更希望大家能不靈賜教,我們共同進步。

    在開始之前,我們先來說說,ASP.NET Web Form 和 Asp.net MVC 有什麼區別,這裡說的區別,當然是本質區別,不是適用語法那個層次的。其實,說起來,ASP.NET WEB FORM 和 ASP.NET MVC 它們兩個沒有本質區別,使用的都是ASP.NET WEB FORM 的管道處理模型,ASP.NET MVC 也是通過擴展 IHttpModule 和 IHttpHandler 來實現的,都是基於 ASP.NET 的 HttpApplication 的管道處理模型擴展的,在這個層面來說,它們是一樣的。當然,大家不要抬杠,我說的本質區別都是在這個方面,不同意的勿噴。

    有人會問,ASP.NET MVC  和 ASP.NET WEBAPI 它們會有什麼不同嗎?好像 WebAPi 能做的,WebMVC都可以完成,第一眼看上去,好像是這樣,但是它們有著本質的不同。WebAPI 的處理管道是重新寫過的,不是基於 HTTPApplication 管道擴展的。ASP.NET WEB API 類似專人做專事,它的管道處理模型更高效,並且有了 Restfull 的概念。當然,大家如何向了解更細的內容,就需要看源碼了。或再說回來,到了 NET CORE 時代,二者又融合管道了。

二、MVC生命周期詳述

    1、我們既然要說 ASP.NET MVC的生命周期,為了給大家一個整體印象,俗話說,文不如圖,我就貼一張圖,按著箭頭走,相信大家也會不能理解。

        

    2、上圖很簡單,大家按著箭頭走,也能理解的差不多。以下是按著我的理解,劃分了4個模組。

        (1)、路由模組

             RouteBase 是對路由規則的抽象,也就是說,一個 RouteBase 對象,也就代表了一個條 路由規則。在 ASP.NET MVC 中,有一個唯一的子類實現就是 Route ,它同樣也是路由規則的代表。我們有了路由規則,一定會把這個規則存放在一個地方,這個地方保存了很多路由規則,這個地方就是 RouteCollection,中文叫「路由集合」,因為這個集合裡面包含的就是 RouteBase 對象。

             RouteCollection 就是路由集合,用於保存路由規則對象,它的定義形式:

 1         [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 2       public class RouteCollection : Collection<RouteBase>
 3       {
 4           private class ReadLockDisposable : IDisposable
 5           {
 6               private ReaderWriterLockSlim _rwLock;
 7 
 8               public ReadLockDisposable(ReaderWriterLockSlim rwLock)
 9               {
10                   this._rwLock = rwLock;
11               }
12 
13               void IDisposable.Dispose()
14               {
15                   this._rwLock.ExitReadLock();
16               }
17           }  
18             ......

             RouteTable 就是路由表,其實它和 RouteCollection 是一樣的。              

 1     public class RouteTable
 2     {
 3         private static RouteCollection _instance = new RouteCollection();
 4 
 5         public static RouteCollection Routes
 6         {
 7             get
 8             {
 9                 return RouteTable._instance;
10             }
11         }
12     }

             在ASP.NET MVC處理管線中的第一站就是路由模組。當請求到達路由模組後,ASP.NET MVC 框架就會根據 RouteTable 中配置的路由模板來匹配當前請求以獲得對應的 Controller 和 Action 資訊。具體的匹配過程就是有UrlRoutingModule(System.Web.Routing.UrlRoutingModule)來實現的。如果遇到一個匹配的規則,就會立刻跳出下面的配置。也就是說,配置過程是有順序的,如果有一個匹配,後面就算有匹配的也不會執行的。
              

  1 namespace System.Web.Routing
  2 {
  3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
  4     public class UrlRoutingModule : IHttpModule
  5     {
  6         private static readonly object _contextKey = new object();
  7 
  8         private static readonly object _requestDataKey = new object();
  9 
 10         private RouteCollection _routeCollection;
 11 
 12         public RouteCollection RouteCollection
 13         {
 14             get
 15             {
 16                 if (this._routeCollection == null)
 17                 {
 18                     this._routeCollection = RouteTable.Routes;
 19                 }
 20                 return this._routeCollection;
 21             }
 22             set
 23             {
 24                 this._routeCollection = value;
 25             }
 26         }
 27 
 28         protected virtual void Dispose()
 29         {
 30         }
 31 
 32         protected virtual void Init(HttpApplication application)
 33         {
 34             if (application.Context.Items[UrlRoutingModule._contextKey] != null)
 35             {
 36                 return;
 37             }
 38             application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey;
 39             application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
 40         }
 41 
 42         private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
 43         {
 44             HttpApplication httpApplication = (HttpApplication)sender;
 45             HttpContextBase context = new HttpContextWrapper(httpApplication.Context);
 46             this.PostResolveRequestCache(context);
 47         }
 48 
 49         [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
 50         public virtual void PostMapRequestHandler(HttpContextBase context)
 51         {
 52         }
 53 
 54         public virtual void PostResolveRequestCache(HttpContextBase context)
 55         {
 56             RouteData routeData = this.RouteCollection.GetRouteData(context); 第一步匹配路由規則
 57             if (routeData == null)
 58             {
 59                 return;
 60             }
 61             IRouteHandler routeHandler = routeData.RouteHandler; 第二步:如有匹配,就找到RouteHandler對象,該類型的實例是:MvcRouteHandler。
 62             if (routeHandler == null)
 63             {
 64                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
 65             }
 66             if (routeHandler is StopRoutingHandler)
 67             {
 68                 return;
 69             }
 70             RequestContext requestContext = new RequestContext(context, routeData);
 71             context.Request.RequestContext = requestContext;
 72             IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);第三步,根據 RouteHandler 對象,找到最終處理請求的 IHttpHandler 的對象,該類型是 MvcHandler
 73             if (httpHandler == null)
 74             {
 75                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[]
 76                 {
 77                     routeHandler.GetType()
 78                 }));
 79             }
 80             if (!(httpHandler is UrlAuthFailureHandler))
 81             {
 82                 context.RemapHandler(httpHandler);第四步,有找到的 IHttpHandler 處理請求。
 83                 return;
 84             }
 85             if (FormsAuthenticationModule.FormsAuthRequired)
 86             {
 87                 UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
 88                 return;
 89             }
 90             throw new HttpException(401, SR.GetString("Assess_Denied_Description3"));
 91         }
 92 
 93         void IHttpModule.Dispose()
 94         {
 95             this.Dispose();
 96         }
 97 
 98         void IHttpModule.Init(HttpApplication application)
 99         {
100             this.Init(application);
101         }
102     }
103 }

        (2)、Controller 創建模組

               經過了路由模組,生成了 RouteData 路由數據,它包含了根據路由規則匹配的 Controller 和 Action。有了路由數據,需要有處理器來處理請求,這個任務就交給了 RouteData 的 RouteHandler 屬性,它的類型是 IRouteHandler,它的值就是MvcRouteHandler,MvcRouteHandler 調用 GetHttpHandler 獲取處理請求的 IHttpHandler 對象,在 MVC 框架中就是 MvcHandler,詳細程式碼如下:

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

View Code

              HttpRuntime 調用 IHttpHandler 類型的調用 ProcessRequest() 方法,用於處理請求。              

 1 protected internal virtual void ProcessRequest(HttpContextBase httpContext)
 2 {
 3     IController controller;
 4     IControllerFactory controllerFactory;
 5     this.ProcessRequestInit(httpContext, out controller, out controllerFactory);創建 IControllerFactory,並創建 IController 對象。
 6     try
 7     {
 8         controller.Execute(this.RequestContext);執行Controller,背後就是調用相應的 Action 方法。
 9     }
10     finally
11     {
12         controllerFactory.ReleaseController(controller);
13     }
14 }

              核心處理請求的方法是ProcessRequestInit(),用於創建 IController 和 IControllerFactory 實例。IControllerFactory 的實際類型是:DefaultControllerFactory,該類型用於創建 IController  類型的實例。

 1 private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
 2 {
 3     HttpContext current = HttpContext.Current;
 4     if (current != null)
 5     {
 6         bool? flag = ValidationUtility.IsValidationEnabled(current);
 7         bool flag2 = true;
 8         if (flag.GetValueOrDefault() == flag2 & flag.HasValue)
 9         {
10             ValidationUtility.EnableDynamicValidation(current);
11         }
12     }
13     this.AddVersionHeader(httpContext);
14     this.RemoveOptionalRoutingParameters();
15     string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
16     factory = this.ControllerBuilder.GetControllerFactory();
17     controller = factory.CreateController(this.RequestContext, requiredString);
18     if (controller == null)
19     {
20         throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[]
21         {
22             factory.GetType(),
23             requiredString
24         }));
25     }
26 }

              以上加紅的程式碼就是創建 IController 的實例的邏輯。IController 實例創建完成後,判斷是否實現了 IAsyncController 介面,如果是,就非同步執行 Controller 方法的調用,否則就同步執行。

 1 protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
 2 {
 3     IController controller;
 4     IControllerFactory factory;
 5     this.ProcessRequestInit(httpContext, out controller, out factory);
 6     IAsyncController asyncController = controller as IAsyncController; 判讀是否是需要非同步執行
 7     if (asyncController != null)非同步執行
 8     {
 9         BeginInvokeDelegate<MvcHandler.ProcessRequestState> arg_51_0;
10         if ((arg_51_0 = MvcHandler.<>c.<>9__20_0) == null)
11         {
12             arg_51_0 = (MvcHandler.<>c.<>9__20_0 = new BeginInvokeDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_0));
13         }
14         BeginInvokeDelegate<MvcHandler.ProcessRequestState> beginDelegate = arg_51_0;
15         EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> arg_71_0;
16         if ((arg_71_0 = MvcHandler.<>c.<>9__20_1) == null)
17         {
18             arg_71_0 = (MvcHandler.<>c.<>9__20_1 = new EndInvokeVoidDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_1));
19         }
20         EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> endDelegate = arg_71_0;
21         MvcHandler.ProcessRequestState invokeState = new MvcHandler.ProcessRequestState
22         {
23             AsyncController = asyncController,
24             Factory = factory,
25             RequestContext = this.RequestContext
26         };
27         SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext();
28         return AsyncResultWrapper.Begin<MvcHandler.ProcessRequestState>(callback, state, beginDelegate, endDelegate, invokeState, MvcHandler._processRequestTag, -1, synchronizationContext);
29     }
30     Action action = delegate//同步執行。
31     {
32         try
33         {
34             controller.Execute(this.RequestContext);
35         }
36         finally
37         {
38             factory.ReleaseController(controller);
39         }
40     };
41     return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag);
42 }

 

        (3)、Action 執行模組,通過 ControllerActionInvoker 調用 InvokeAction() 執行其方法。Action 方法的執行也有2個版本,一個是非同步版本,一個是同步版本。由於 ActionInvoker 實現了 IAsyncActionInvoker 介面,所以也是以已方式執行。該類型是 AsyncControllerActionInvoker。

             A、當Controller對象被創建之後,緊接著就會執行Controler 對象的 Execute(),其實背後就是調用 InvokeAction() 方法:
                

 1 public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
 2 {
 3     if (controllerContext == null)
 4     {
 5         throw new ArgumentNullException("controllerContext");
 6     }
 7     if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
 8     {
 9         throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
10     }
11     ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
12     ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
13     if (actionDescriptor != null)
14     {
15         FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor); 獲取所有過濾器,全局的、控制器的和方法的
16         try
17         {
18             AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);認證過濾器的執行。
19             if (authenticationContext.Result != null)
20             {
21                 AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
22                 this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);
23             }
24             else
25             {
26                 AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);授權過濾器的執行。
27                 if (authorizationContext.Result != null)
28                 {
29                     AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
30                     this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result);
31                 }
32                 else
33                 {
34                     if (controllerContext.Controller.ValidateRequest)
35                     {
36                         ControllerActionInvoker.ValidateRequest(controllerContext);
37                     }
38                     IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor); 獲取方法執行參數。
39                     ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues); 執行action,同時執行執行方法前後的 IAcctionFilter
40                     AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result);
41                     this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result); 執行 ActionResult,同時執行方法前後的 IResultFilter 
42                 }
43             }
44         }
45         catch (ThreadAbortException)
46         {
47             throw;
48         }
49         catch (Exception exception)
50         {
51             ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
52             if (!exceptionContext.ExceptionHandled)
53             {
54                 throw;
55             }
56             this.InvokeActionResult(controllerContext, exceptionContext.Result);//異常過濾器的執行。
57         }
58         return true;
59     }
60     return false;
61 }

            B、當選擇完合適的Action後,接著就是 ModelBinder(默認是System.Web.Mvc.DefaultModelBinder),它會從http請求的參數中提取數據並實現類型轉換,數據校驗(例如是否必填,數據格式等)以及是否自動裝配到action方法的參數中System.Web.Mvc.DefaultModelBinder

 1 protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
 2 {
 3     Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
 4     ParameterDescriptor[] parameters = actionDescriptor.GetParameters();
 5     for (int i = 0; i < parameters.Length; i++)
 6     {
 7         ParameterDescriptor parameterDescriptor = parameters[i];
 8         dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor);
 9     }
10     return dictionary;
11 }
 1 protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
 2 {
 3     Type parameterType = parameterDescriptor.ParameterType;
 4     IModelBinder arg_92_0 = this.GetModelBinder(parameterDescriptor);
 5     IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
 6     string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
 7     Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);
 8     ModelBindingContext bindingContext = new ModelBindingContext
 9     {
10         FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,
11         ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
12         ModelName = modelName,
13         ModelState = controllerContext.Controller.ViewData.ModelState,
14         PropertyFilter = propertyFilter,
15         ValueProvider = valueProvider
16     };
17     return arg_92_0.BindModel(controllerContext, bindingContext) ?? parameterDescriptor.DefaultValue;
18 }

            C、Authentication Filter是mvc5中新增的一個Filter,它會先於authorization filter執行,目的是對訪問用戶的認證。在MVC5之前,認證和授權都是通過authorization filter來實現的,但現在這2個操作就分開來了,各自管各自嘍。

1        AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);
2             if (authenticationContext.Result != null)
3             {
4                 AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
5                 this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);
6             }

            D、Action filters有2個方法OnActionExecuting和OnActionExecuted分別在action執行前後執行。我們也可以通過實現IActionFilter介面來實現你個性化的過濾機制

1 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
2 {
3     ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
4     Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
5     {
6         Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
7     };
8     return filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next))();
9 }

            E、接下來就是執行我們平時在Action方法中寫的程式碼了(根據請求相應結果)

1 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
2 {
3     object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
4     return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
5 }

 

        (4)、ActionResult 執行模組。

             A、在 ActionResult 執行前後,仍然會有一個filter(IResultFilter),同樣的,通過實現 IResultFilter 介面你可以訂製自己的過濾邏輯。

 1 namespace System.Web.Mvc
 2 {
 3     /// <summary>Defines the methods that are required for a result filter.</summary>
 4     public interface IResultFilter
 5     {
 6         /// <summary>Called before an action result executes.</summary>
 7         /// <param name="filterContext">The filter context.</param>
 8         void OnResultExecuting(ResultExecutingContext filterContext);
 9 
10         /// <summary>Called after an action result executes.</summary>
11         /// <param name="filterContext">The filter context.</param>
12         void OnResultExecuted(ResultExecutedContext filterContext);
13     }
14 }

             B、ActionResult 就是把處理的用戶請求結果返回。因此 ViewResult, PartialViewResult, RedirectToRouteResult, RedirectResult, ContentResult, JsonResult, FileResult and EmptyResult就是具體的返回類型。

             C、上面的返回類型可以大致分為2類:ViewResult 和非ViewResult。對於需要生成html頁面給客戶端的划到ViewResult,而其他的例如返迴文本,json數據等則劃分到非ViewResult,對於非ViewResult直接返回就可以了。

            View的初始化和渲染呈現

             A、對於 ViewResult 最終是由合適的 View Engine 通過調用 IView 的 Render() 方法來渲染的:

 1 namespace System.Web.Mvc
 2 {
 3     /// <summary>Defines the methods that are required for a view engine.</summary>
 4     public interface IViewEngine
 5     {
 6         /// <summary>Finds the specified partial view by using the specified controller context.</summary>
 7         /// <returns>The partial view.</returns>
 8         /// <param name="controllerContext">The controller context.</param>
 9         /// <param name="partialViewName">The name of the partial view.</param>
10         /// <param name="useCache">true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false.</param>
11         ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
12 
13         /// <summary>Finds the specified view by using the specified controller context.</summary>
14         /// <returns>The page view.</returns>
15         /// <param name="controllerContext">The controller context.</param>
16         /// <param name="viewName">The name of the view.</param>
17         /// <param name="masterName">The name of the master.</param>
18         /// <param name="useCache">true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false.</param>
19         ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
20 
21         /// <summary>Releases the specified view by using the specified controller context.</summary>
22         /// <param name="controllerContext">The controller context.</param>
23         /// <param name="view">The view.</param>
24         void ReleaseView(ControllerContext controllerContext, IView view);
25     }
26 }

 

 1 namespace System.Web.Mvc
 2 {
 3     /// <summary>Defines the methods that are required for a view.</summary>
 4     public interface IView
 5     {
 6         /// <summary>Renders the specified view context by using the specified the writer object.</summary>
 7         /// <param name="viewContext">The view context.</param>
 8         /// <param name="writer">The writer object.</param>
 9         void Render(ViewContext viewContext, TextWriter writer);
10     }
11 }

             B、整個處理過程是由 IViewEngine 來實現的。ASP.NET MVC 默認提供 WebForm(.aspx)和 Razor(.cshtml) 模板引擎,你可以通過實現 IViewEngine 介面來實現自己的 ViewEngine,然後在Application_Start方法中做如下註冊:

protected void Application_Start()
{
 //移除所有的View引擎包括Webform和Razor
 ViewEngines.Engines.Clear();
 //註冊你自己的View引擎

 ViewEngines.Engines.Add(new CustomViewEngine());
 
}

             C、最後,Html Helpers將幫我們生成 input 標籤,基於AJAX的 form 等等。

 

        (5)、作為總結,將每個節點主要的程式碼類貼出來。

            這就是整個流程的程式碼節點,有些是同步執行,有些是非同步執行,把握關鍵點,我這裡只是謝了一個大概。

            UrlRoutingModule—–RouteCollection.GetRouteData(context)—–>IRouteHandler routeHandler = routeData.RouteHandler——》IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext)—–》context.RemapHandler(httpHandler)——->MvcHandler——->ProcessRequest()——>ProcessRequestInit()——–》IController——>controller.Execute(this.RequestContext)——–>ControllerActionInvoker——->InvoleAction()———>InvoleActionMethod()——->InvoleActionReslt()

三、結束

    今天就到這裡了,東西雖然不多,但是也寫了2個多小時。今天就算自己有學習了一邊,大家一定要好好的把握這個流程,對於解決程式中的問題,擴展框架都有很大的好處。我們作為程式設計師的,應該要知道其一,也要知道其二。沒事,看看源碼,我們對框架和我們自己的程式碼有更深的了解。當然,這樣做也是有代價的,需要更多的時間去支援,我相信我們的付出是值得。不忘初心,繼續努力。老天不會辜負努力的人。