詳解ASP.NET MVC的整個(gè)生命周期
一、介紹
我們做開發(fā)的,尤其是做微軟技術(shù)棧的,有一個(gè)方向是跳不過去的,那就是MVC開發(fā)。我相信大家,做ASP.NET MVC 開發(fā)有的有很長(zhǎng)時(shí)間,當(dāng)然,也有剛進(jìn)入這個(gè)行業(yè)的。無論如何,如果有人問你,你知道ASP.NET MVC的生命周期嗎?你知道它的來世今生嗎?你知道它和 ASP.NET WEBFORM 有什么區(qū)別嗎?估計(jì),這些問題,有很多人會(huì)答不上來,或者說不清楚。今天,我就把我的理解寫出來,也是對(duì)我自己學(xué)習(xí)的一次回顧和總結(jié)吧。當(dāng)然,由于本人能力有限,在寫的過程中也可能會(huì)有一些錯(cuò)誤,希望大家多多包涵,當(dāng)然,更希望大家能不靈賜教,我們共同進(jìn)步。
在開始之前,我們先來說說,ASP.NET Web Form 和 Asp.net MVC 有什么區(qū)別,這里說的區(qū)別,當(dāng)然是本質(zhì)區(qū)別,不是適用語法那個(gè)層次的。其實(shí),說起來,ASP.NET WEB FORM 和 ASP.NET MVC 它們兩個(gè)沒有本質(zhì)區(qū)別,使用的都是ASP.NET WEB FORM 的管道處理模型,ASP.NET MVC 也是通過擴(kuò)展 IHttpModule 和 IHttpHandler 來實(shí)現(xiàn)的,都是基于 ASP.NET 的 HttpApplication 的管道處理模型擴(kuò)展的,在這個(gè)層面來說,它們是一樣的。當(dāng)然,大家不要抬杠,我說的本質(zhì)區(qū)別都是在這個(gè)方面,不同意的勿噴。
有人會(huì)問,ASP.NET MVC 和 ASP.NET WEBAPI 它們會(huì)有什么不同嗎?好像 WebAPi 能做的,WebMVC都可以完成,第一眼看上去,好像是這樣,但是它們有著本質(zhì)的不同。WebAPI 的處理管道是重新寫過的,不是基于 HTTPApplication 管道擴(kuò)展的。ASP.NET WEB API 類似專人做專事,它的管道處理模型更高效,并且有了 Restfull 的概念。當(dāng)然,大家如何向了解更細(xì)的內(nèi)容,就需要看源碼了?;蛟僬f回來,到了 NET CORE 時(shí)代,二者又融合管道了。
二、MVC生命周期詳述
1、我們既然要說 ASP.NET MVC的生命周期,為了給大家一個(gè)整體印象,俗話說,文不如圖,我就貼一張圖,按著箭頭走,相信大家也會(huì)不能理解。
2、上圖很簡(jiǎn)單,大家按著箭頭走,也能理解的差不多。以下是按著我的理解,劃分了4個(gè)模塊。
(1)、路由模塊
RouteBase 是對(duì)路由規(guī)則的抽象,也就是說,一個(gè) RouteBase 對(duì)象,也就代表了一個(gè)條 路由規(guī)則。在 ASP.NET MVC 中,有一個(gè)唯一的子類實(shí)現(xiàn)就是 Route ,它同樣也是路由規(guī)則的代表。我們有了路由規(guī)則,一定會(huì)把這個(gè)規(guī)則存放在一個(gè)地方,這個(gè)地方保存了很多路由規(guī)則,這個(gè)地方就是 RouteCollection,中文叫“路由集合”,因?yàn)檫@個(gè)集合里面包含的就是 RouteBase 對(duì)象。
RouteCollection 就是路由集合,用于保存路由規(guī)則對(duì)象,它的定義形式:
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public class RouteCollection : Collection<RouteBase> { private class ReadLockDisposable : IDisposable { private ReaderWriterLockSlim _rwLock; public ReadLockDisposable(ReaderWriterLockSlim rwLock) { this._rwLock = rwLock; } void IDisposable.Dispose() { this._rwLock.ExitReadLock(); } } ......
RouteTable 就是路由表,其實(shí)它和 RouteCollection 是一樣的。
public class RouteTable { private static RouteCollection _instance = new RouteCollection(); public static RouteCollection Routes { get { return RouteTable._instance; } } }
在ASP.NET MVC處理管線中的第一站就是路由模塊。當(dāng)請(qǐng)求到達(dá)路由模塊后,ASP.NET MVC 框架就會(huì)根據(jù) RouteTable 中配置的路由模板來匹配當(dāng)前請(qǐng)求以獲得對(duì)應(yīng)的 Controller 和 Action 信息。具體的匹配過程就是有UrlRoutingModule(System.Web.Routing.UrlRoutingModule)來實(shí)現(xiàn)的。如果遇到一個(gè)匹配的規(guī)則,就會(huì)立刻跳出下面的配置。也就是說,配置過程是有順序的,如果有一個(gè)匹配,后面就算有匹配的也不會(huì)執(zhí)行的。
namespace System.Web.Routing { [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public class UrlRoutingModule : IHttpModule { private static readonly object _contextKey = new object(); private static readonly object _requestDataKey = new object(); private RouteCollection _routeCollection; public RouteCollection RouteCollection { get { if (this._routeCollection == null) { this._routeCollection = RouteTable.Routes; } return this._routeCollection; } set { this._routeCollection = value; } } protected virtual void Dispose() { } protected virtual void Init(HttpApplication application) { if (application.Context.Items[UrlRoutingModule._contextKey] != null) { return; } application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey; application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpApplication httpApplication = (HttpApplication)sender; HttpContextBase context = new HttpContextWrapper(httpApplication.Context); this.PostResolveRequestCache(context); } [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")] public virtual void PostMapRequestHandler(HttpContextBase context) { } public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); 第一步匹配路由規(guī)則 if (routeData == null) { return; } IRouteHandler routeHandler = routeData.RouteHandler; 第二步:如有匹配,就找到RouteHandler對(duì)象,該類型的實(shí)例是:MvcRouteHandler。 if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } if (routeHandler is StopRoutingHandler) { return; } RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);第三步,根據(jù) RouteHandler 對(duì)象,找到最終處理請(qǐng)求的 IHttpHandler 的對(duì)象,該類型是 MvcHandler if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (!(httpHandler is UrlAuthFailureHandler)) { context.RemapHandler(httpHandler);第四步,有找到的 IHttpHandler 處理請(qǐng)求。 return; } if (FormsAuthenticationModule.FormsAuthRequired) { UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); return; } throw new HttpException(401, SR.GetString("Assess_Denied_Description3")); } void IHttpModule.Dispose() { this.Dispose(); } void IHttpModule.Init(HttpApplication application) { this.Init(application); } } }
(2)、Controller 創(chuàng)建模塊
經(jīng)過了路由模塊,生成了 RouteData 路由數(shù)據(jù),它包含了根據(jù)路由規(guī)則匹配的 Controller 和 Action。有了路由數(shù)據(jù),需要有處理器來處理請(qǐng)求,這個(gè)任務(wù)就交給了 RouteData 的 RouteHandler 屬性,它的類型是 IRouteHandler,它的值就是MvcRouteHandler,MvcRouteHandler 調(diào)用 GetHttpHandler 獲取處理請(qǐng)求的 IHttpHandler 對(duì)象,在 MVC 框架中就是 MvcHandler,詳細(xì)代碼如下:
namespace System.Web.Mvc { /// <summary>Selects the controller that will handle an HTTP request.</summary> public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState { private struct ProcessRequestState { internal IAsyncController AsyncController; internal IControllerFactory Factory; internal RequestContext RequestContext; internal void ReleaseController() { this.Factory.ReleaseController(this.AsyncController); } } [CompilerGenerated] [Serializable] private sealed class <>c { public static readonly MvcHandler.<>c <>9 = new MvcHandler.<>c(); public static BeginInvokeDelegate<MvcHandler.ProcessRequestState> <>9__20_0; public static EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> <>9__20_1; public static Func<KeyValuePair<string, object>, bool> <>9__26_0; internal IAsyncResult <BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState) { IAsyncResult result; try { result = innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState); } catch { innerState.ReleaseController(); throw; } return result; } internal void <BeginProcessRequest>b__20_1(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState) { try { innerState.AsyncController.EndExecute(asyncResult); } finally { innerState.ReleaseController(); } } internal bool <RemoveOptionalRoutingParameters>b__26_0(KeyValuePair<string, object> entry) { return entry.Value == UrlParameter.Optional; } } private static readonly object _processRequestTag = new object(); internal static readonly string MvcVersion = MvcHandler.GetMvcVersionString(); /// <summary>Contains the header name of the ASP.NET MVC version.</summary> public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version"; private ControllerBuilder _controllerBuilder; internal ControllerBuilder ControllerBuilder { get { if (this._controllerBuilder == null) { this._controllerBuilder = ControllerBuilder.Current; } return this._controllerBuilder; } set { this._controllerBuilder = value; } } /// <summary>Gets or sets a value that indicates whether the MVC response header is disabled.</summary> /// <returns>true if the MVC response header is disabled; otherwise, false.</returns> public static bool DisableMvcResponseHeader { get; set; } /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary> /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns> protected virtual bool IsReusable { get { return false; } } /// <summary>Gets the request context.</summary> /// <returns>The request context.</returns> public RequestContext RequestContext { get; private set; } /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary> /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns> bool IHttpHandler.IsReusable { get { return this.IsReusable; } } /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.MvcHandler" /> class.</summary> /// <param name="requestContext">The request context.</param> /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext" /> parameter is null.</exception> public MvcHandler(RequestContext requestContext) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } this.RequestContext = requestContext; } /// <summary>Adds the version header by using the specified HTTP context.</summary> /// <param name="httpContext">The HTTP context.</param> protected internal virtual void AddVersionHeader(HttpContextBase httpContext) { if (!MvcHandler.DisableMvcResponseHeader) { httpContext.Response.AppendHeader(MvcHandler.MvcVersionHeaderName, MvcHandler.MvcVersion); } } /// <summary>Called by ASP.NET to begin asynchronous request processing.</summary> /// <returns>The status of the asynchronous call.</returns> /// <param name="httpContext">The HTTP context.</param> /// <param name="callback">The asynchronous callback method.</param> /// <param name="state">The state of the asynchronous object.</param> protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) { HttpContextBase httpContext2 = new HttpContextWrapper(httpContext); return this.BeginProcessRequest(httpContext2, callback, state); } /// <summary>Called by ASP.NET to begin asynchronous request processing using the base HTTP context.</summary> /// <returns>The status of the asynchronous call.</returns> /// <param name="httpContext">The HTTP context.</param> /// <param name="callback">The asynchronous callback method.</param> /// <param name="state">The state of the asynchronous object.</param> protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { IController controller; IControllerFactory factory; this.ProcessRequestInit(httpContext, out controller, out factory); IAsyncController asyncController = controller as IAsyncController; if (asyncController != null) { BeginInvokeDelegate<MvcHandler.ProcessRequestState> arg_51_0; if ((arg_51_0 = MvcHandler.<>c.<>9__20_0) == null) { arg_51_0 = (MvcHandler.<>c.<>9__20_0 = new BeginInvokeDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_0)); } BeginInvokeDelegate<MvcHandler.ProcessRequestState> beginDelegate = arg_51_0; EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> arg_71_0; if ((arg_71_0 = MvcHandler.<>c.<>9__20_1) == null) { arg_71_0 = (MvcHandler.<>c.<>9__20_1 = new EndInvokeVoidDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_1)); } EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> endDelegate = arg_71_0; MvcHandler.ProcessRequestState invokeState = new MvcHandler.ProcessRequestState { AsyncController = asyncController, Factory = factory, RequestContext = this.RequestContext }; SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext(); return AsyncResultWrapper.Begin<MvcHandler.ProcessRequestState>(callback, state, beginDelegate, endDelegate, invokeState, MvcHandler._processRequestTag, -1, synchronizationContext); } Action action = delegate { try { controller.Execute(this.RequestContext); } finally { factory.ReleaseController(controller); } }; return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag); } /// <summary>Called by ASP.NET when asynchronous request processing has ended.</summary> /// <param name="asyncResult">The asynchronous result.</param> protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) { AsyncResultWrapper.End(asyncResult, MvcHandler._processRequestTag); } private static string GetMvcVersionString() { return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2); } /// <summary>Processes the request by using the specified HTTP request context.</summary> /// <param name="httpContext">The HTTP context.</param> protected virtual void ProcessRequest(HttpContext httpContext) { HttpContextBase httpContext2 = new HttpContextWrapper(httpContext); this.ProcessRequest(httpContext2); } /// <summary>Processes the request by using the specified base HTTP request context.</summary> /// <param name="httpContext">The HTTP context.</param> protected internal virtual void ProcessRequest(HttpContextBase httpContext) { IController controller; IControllerFactory controllerFactory; this.ProcessRequestInit(httpContext, out controller, out controllerFactory); try { controller.Execute(this.RequestContext); } finally { controllerFactory.ReleaseController(controller); } } private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { HttpContext current = HttpContext.Current; if (current != null) { bool? flag = ValidationUtility.IsValidationEnabled(current); bool flag2 = true; if (flag.GetValueOrDefault() == flag2 & flag.HasValue) { ValidationUtility.EnableDynamicValidation(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 })); } } private void RemoveOptionalRoutingParameters() { IDictionary<string, object> arg_2F_0 = this.RequestContext.RouteData.Values; Func<KeyValuePair<string, object>, bool> arg_2F_1; if ((arg_2F_1 = MvcHandler.<>c.<>9__26_0) == null) { arg_2F_1 = (MvcHandler.<>c.<>9__26_0 = new Func<KeyValuePair<string, object>, bool>(MvcHandler.<>c.<>9.<RemoveOptionalRoutingParameters>b__26_0)); } arg_2F_0.RemoveFromDictionary(arg_2F_1); } /// <summary>Enables processing of HTTP Web requests by a custom HTTP handler that implements the <see cref="T:System.Web.IHttpHandler" /> interface.</summary> /// <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> void IHttpHandler.ProcessRequest(HttpContext httpContext) { this.ProcessRequest(httpContext); } /// <summary>Called by ASP.NET to begin asynchronous request processing using the base HTTP context.</summary> /// <returns>The status of the asynchronous call.</returns> /// <param name="context">The HTTP context.</param> /// <param name="cb">The asynchronous callback method.</param> /// <param name="extraData">The data.</param> IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { return this.BeginProcessRequest(context, cb, extraData); } /// <summary>Called by ASP.NET when asynchronous request processing has ended.</summary> /// <param name="result">The asynchronous result.</param> void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { this.EndProcessRequest(result); } } } HttpRuntime 調(diào)用 IHttpHandler 類型的調(diào)用 ProcessRequest() 方法,用于處理請(qǐng)求。 protected internal virtual void ProcessRequest(HttpContextBase httpContext) { IController controller; IControllerFactory controllerFactory; this.ProcessRequestInit(httpContext, out controller, out controllerFactory);創(chuàng)建 IControllerFactory,并創(chuàng)建 IController 對(duì)象。 try { controller.Execute(this.RequestContext);執(zhí)行Controller,背后就是調(diào)用相應(yīng)的 Action 方法。 } finally { controllerFactory.ReleaseController(controller); } }
核心處理請(qǐng)求的方法是ProcessRequestInit(),用于創(chuàng)建 IController 和 IControllerFactory 實(shí)例。IControllerFactory 的實(shí)際類型是:DefaultControllerFactory,該類型用于創(chuàng)建 IController 類型的實(shí)例。
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { HttpContext current = HttpContext.Current; if (current != null) { bool? flag = ValidationUtility.IsValidationEnabled(current); bool flag2 = true; if (flag.GetValueOrDefault() == flag2 & flag.HasValue) { ValidationUtility.EnableDynamicValidation(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 })); } }
以上加紅的代碼就是創(chuàng)建 IController 的實(shí)例的邏輯。IController 實(shí)例創(chuàng)建完成后,判斷是否實(shí)現(xiàn)了 IAsyncController 接口,如果是,就異步執(zhí)行 Controller 方法的調(diào)用,否則就同步執(zhí)行。
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { IController controller; IControllerFactory factory; this.ProcessRequestInit(httpContext, out controller, out factory); IAsyncController asyncController = controller as IAsyncController; 判讀是否是需要異步執(zhí)行 if (asyncController != null)異步執(zhí)行 { BeginInvokeDelegate<MvcHandler.ProcessRequestState> arg_51_0; if ((arg_51_0 = MvcHandler.<>c.<>9__20_0) == null) { arg_51_0 = (MvcHandler.<>c.<>9__20_0 = new BeginInvokeDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_0)); } BeginInvokeDelegate<MvcHandler.ProcessRequestState> beginDelegate = arg_51_0; EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> arg_71_0; if ((arg_71_0 = MvcHandler.<>c.<>9__20_1) == null) { arg_71_0 = (MvcHandler.<>c.<>9__20_1 = new EndInvokeVoidDelegate<MvcHandler.ProcessRequestState>(MvcHandler.<>c.<>9.<BeginProcessRequest>b__20_1)); } EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> endDelegate = arg_71_0; MvcHandler.ProcessRequestState invokeState = new MvcHandler.ProcessRequestState { AsyncController = asyncController, Factory = factory, RequestContext = this.RequestContext }; SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext(); return AsyncResultWrapper.Begin<MvcHandler.ProcessRequestState>(callback, state, beginDelegate, endDelegate, invokeState, MvcHandler._processRequestTag, -1, synchronizationContext); } Action action = delegate//同步執(zhí)行。 { try { controller.Execute(this.RequestContext); } finally { factory.ReleaseController(controller); } }; return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag); }
(3)、Action 執(zhí)行模塊,通過 ControllerActionInvoker 調(diào)用 InvokeAction() 執(zhí)行其方法。Action 方法的執(zhí)行也有2個(gè)版本,一個(gè)是異步版本,一個(gè)是同步版本。由于 ActionInvoker 實(shí)現(xiàn)了 IAsyncActionInvoker 接口,所以也是以已方式執(zhí)行。該類型是 AsyncControllerActionInvoker。
A、當(dāng)Controller對(duì)象被創(chuàng)建之后,緊接著就會(huì)執(zhí)行Controler 對(duì)象的 Execute(),其實(shí)背后就是調(diào)用 InvokeAction() 方法:
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch()) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName"); } ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor); 獲取所有過濾器,全局的、控制器的和方法的 try { AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);認(rèn)證過濾器的執(zhí)行。 if (authenticationContext.Result != null) { AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result); this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result); } else { AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);授權(quán)過濾器的執(zhí)行。 if (authorizationContext.Result != null) { AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result); this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result); } else { if (controllerContext.Controller.ValidateRequest) { ControllerActionInvoker.ValidateRequest(controllerContext); } IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor); 獲取方法執(zhí)行參數(shù)。 ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues); 執(zhí)行action,同時(shí)執(zhí)行執(zhí)行方法前后的 IAcctionFilter AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result); this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result); 執(zhí)行 ActionResult,同時(shí)執(zhí)行方法前后的 IResultFilter } } } catch (ThreadAbortException) { throw; } catch (Exception exception) { ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception); if (!exceptionContext.ExceptionHandled) { throw; } this.InvokeActionResult(controllerContext, exceptionContext.Result);//異常過濾器的執(zhí)行。 } return true; } return false; }
B、當(dāng)選擇完合適的Action后,接著就是 ModelBinder(默認(rèn)是System.Web.Mvc.DefaultModelBinder),它會(huì)從http請(qǐng)求的參數(shù)中提取數(shù)據(jù)并實(shí)現(xiàn)類型轉(zhuǎn)換,數(shù)據(jù)校驗(yàn)(例如是否必填,數(shù)據(jù)格式等)以及是否自動(dòng)裝配到action方法的參數(shù)中System.Web.Mvc.DefaultModelBinder
protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); ParameterDescriptor[] parameters = actionDescriptor.GetParameters(); for (int i = 0; i < parameters.Length; i++) { ParameterDescriptor parameterDescriptor = parameters[i]; dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor); } return dictionary; } protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) { Type parameterType = parameterDescriptor.ParameterType; IModelBinder arg_92_0 = this.GetModelBinder(parameterDescriptor); IValueProvider valueProvider = controllerContext.Controller.ValueProvider; string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName; Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor); ModelBindingContext bindingContext = new ModelBindingContext { FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null, ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType), ModelName = modelName, ModelState = controllerContext.Controller.ViewData.ModelState, PropertyFilter = propertyFilter, ValueProvider = valueProvider }; return arg_92_0.BindModel(controllerContext, bindingContext) ?? parameterDescriptor.DefaultValue; }
C、Authentication Filter是mvc5中新增的一個(gè)Filter,它會(huì)先于authorization filter執(zhí)行,目的是對(duì)訪問用戶的認(rèn)證。在MVC5之前,認(rèn)證和授權(quán)都是通過authorization filter來實(shí)現(xiàn)的,但現(xiàn)在這2個(gè)操作就分開來了,各自管各自嘍。
AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor); if (authenticationContext.Result != null) { AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result); this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result); }
D、Action filters有2個(gè)方法OnActionExecuting和OnActionExecuted分別在action執(zhí)行前后執(zhí)行。我們也可以通過實(shí)現(xiàn)IActionFilter接口來實(shí)現(xiàn)你個(gè)性化的過濾機(jī)制
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(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next))(); }
E、接下來就是執(zhí)行我們平時(shí)在Action方法中寫的代碼了(根據(jù)請(qǐng)求相應(yīng)結(jié)果)
protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) { object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters); return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue); }
(4)、ActionResult 執(zhí)行模塊。
A、在 ActionResult 執(zhí)行前后,仍然會(huì)有一個(gè)filter(IResultFilter),同樣的,通過實(shí)現(xiàn) IResultFilter 接口你可以定制自己的過濾邏輯。
namespace System.Web.Mvc { /// <summary>Defines the methods that are required for a result filter.</summary> public interface IResultFilter { /// <summary>Called before an action result executes.</summary> /// <param name="filterContext">The filter context.</param> void OnResultExecuting(ResultExecutingContext filterContext); /// <summary>Called after an action result executes.</summary> /// <param name="filterContext">The filter context.</param> void OnResultExecuted(ResultExecutedContext filterContext); } }
B、ActionResult 就是把處理的用戶請(qǐng)求結(jié)果返回。因此 ViewResult, PartialViewResult, RedirectToRouteResult, RedirectResult, ContentResult, JsonResult, FileResult and EmptyResult就是具體的返回類型。
C、上面的返回類型可以大致分為2類:ViewResult 和非ViewResult。對(duì)于需要生成html頁(yè)面給客戶端的劃到ViewResult,而其他的例如返回文本,json數(shù)據(jù)等則劃分到非ViewResult,對(duì)于非ViewResult直接返回就可以了。
View的初始化和渲染呈現(xiàn)
A、對(duì)于 ViewResult 最終是由合適的 View Engine 通過調(diào)用 IView 的 Render() 方法來渲染的:
namespace System.Web.Mvc { /// <summary>Defines the methods that are required for a view engine.</summary> public interface IViewEngine { /// <summary>Finds the specified partial view by using the specified controller context.</summary> /// <returns>The partial view.</returns> /// <param name="controllerContext">The controller context.</param> /// <param name="partialViewName">The name of the partial view.</param> /// <param name="useCache">true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false.</param> ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache); /// <summary>Finds the specified view by using the specified controller context.</summary> /// <returns>The page view.</returns> /// <param name="controllerContext">The controller context.</param> /// <param name="viewName">The name of the view.</param> /// <param name="masterName">The name of the master.</param> /// <param name="useCache">true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false.</param> ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache); /// <summary>Releases the specified view by using the specified controller context.</summary> /// <param name="controllerContext">The controller context.</param> /// <param name="view">The view.</param> void ReleaseView(ControllerContext controllerContext, IView view); } }
namespace System.Web.Mvc { /// <summary>Defines the methods that are required for a view.</summary> public interface IView { /// <summary>Renders the specified view context by using the specified the writer object.</summary> /// <param name="viewContext">The view context.</param> /// <param name="writer">The writer object.</param> void Render(ViewContext viewContext, TextWriter writer); } }
B、整個(gè)處理過程是由 IViewEngine 來實(shí)現(xiàn)的。ASP.NET MVC 默認(rèn)提供 WebForm(.aspx)和 Razor(.cshtml) 模板引擎,你可以通過實(shí)現(xiàn) IViewEngine 接口來實(shí)現(xiàn)自己的 ViewEngine,然后在Application_Start方法中做如下注冊(cè):
protected void Application_Start() { //移除所有的View引擎包括Webform和Razor ViewEngines.Engines.Clear(); //注冊(cè)你自己的View引擎 ViewEngines.Engines.Add(new CustomViewEngine()); }
C、最后,Html Helpers將幫我們生成 input 標(biāo)簽,基于AJAX的 form 等等。
(5)、作為總結(jié),將每個(gè)節(jié)點(diǎn)主要的代碼類貼出來。
這就是整個(gè)流程的代碼節(jié)點(diǎn),有些是同步執(zhí)行,有些是異步執(zhí)行,把握關(guān)鍵點(diǎn),我這里只是謝了一個(gè)大概。
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()
三、結(jié)束
今天就到這里了,東西雖然不多,但是也寫了2個(gè)多小時(shí)。今天就算自己有學(xué)習(xí)了一邊,大家一定要好好的把握這個(gè)流程,對(duì)于解決程序中的問題,擴(kuò)展框架都有很大的好處。我們作為程序員的,應(yīng)該要知道其一,也要知道其二。沒事,看看源碼,我們對(duì)框架和我們自己的代碼有更深的了解。當(dāng)然,這樣做也是有代價(jià)的,需要更多的時(shí)間去支持,我相信我們的付出是值得。不忘初心,繼續(xù)努力。老天不會(huì)辜負(fù)努力的人。
到此這篇關(guān)于詳解ASP.NET MVC的整個(gè)生命周期的文章就介紹到這了,更多相關(guān)ASP.NET MVC 生命周期內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp.net Menu控件+SQLServer實(shí)現(xiàn)動(dòng)態(tài)多級(jí)菜單
asp.net Menu控件+SQLServer實(shí)現(xiàn)動(dòng)態(tài)多級(jí)菜單的代碼,需要的朋友可以參考下。2011-12-12Asp.net MVC 對(duì)所有用戶輸入的字符串字段做Trim處理的方法
這篇文章主要介紹了Asp.net MVC 如何對(duì)所有用戶輸入的字符串字段做Trim處理,需要的朋友可以參考下2017-06-06ASP.NET Core擴(kuò)展庫(kù)之Http日志的使用詳解
這篇文章主要介紹了ASP.NET Core擴(kuò)展庫(kù)之Http日志的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用.net技術(shù),感興趣的朋友可以了解下2021-04-04asp.net?web?api2設(shè)置默認(rèn)啟動(dòng)登錄頁(yè)面的方法
這篇文章主要介紹了asp.net?web?api2設(shè)置默認(rèn)啟動(dòng)登錄頁(yè)面的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09ASP.NET MVC實(shí)現(xiàn)批量文件上傳
這篇文章主要為大家詳細(xì)介紹了ASP.NET MVC實(shí)現(xiàn)批量文件上傳,簡(jiǎn)單介紹單文件上傳的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09MS SQL 實(shí)現(xiàn)驗(yàn)證字符串是否包含有大小寫字母的功能
這篇文章主要介紹了MS SQL 實(shí)現(xiàn)驗(yàn)證字符串是否包含有大小寫字母的功能的相關(guān)資料,這樣的功能通常應(yīng)用在字符串的復(fù)雜度需要的朋友可以參考下2016-11-11asp.net模板引擎Razor中cacheName的問題分析
這篇文章主要介紹了asp.net模板引擎Razor中cacheName的問題,實(shí)例分析了cacheName在提高編譯效率方面的使用技巧,需要的朋友可以參考下2015-06-06asp.net編程獲取項(xiàng)目根目錄實(shí)現(xiàn)方法集合
這篇文章主要介紹了asp.net編程獲取項(xiàng)目根目錄實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析總結(jié)了asp.net針對(duì)項(xiàng)目目錄的操作技巧與注意事項(xiàng),需要的朋友可以參考下2015-11-11asp.net下Linq To Sql注意事項(xiàng)小結(jié)
對(duì)于Linq 連接數(shù)據(jù)庫(kù)進(jìn)行操作時(shí)需注意的問題2008-10-10一步步打造簡(jiǎn)單的MVC電商網(wǎng)站BooksStore(3)
這篇文章主要和大家一起一步步打造一個(gè)簡(jiǎn)單的MVC電商網(wǎng)站,MVC電商網(wǎng)站BooksStore第三篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04