上篇博文《白話學習MVC(七)Action的執行一》介紹了ASP.NET MVC中Action的執行的簡要流程,而且對TempData的運行機制進行了詳細的分析,本篇來分析上一篇中遺留的【3-二、ActionInvoker.InvokeAction(ControllerContext, actionName)】部分的內容,其中包含了Action的執行、過濾器的執行、View的呈現(下節介紹)。
html
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter {protected override void ExecuteCore() { //獲取上次處理過程當中沒有被使用的TempData PossiblyLoadTempData(); try { //從路由數據中獲取請求的Action的名字 string actionName = RouteData.GetRequiredString("action"); if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { //將TempData保存到Session中。等待以後將Session的key【__ControllerTempData】發送到響應流中! PossiblySaveTempData(); } } }
概述中的紅色字體部分,也就是咱們上一節中遺留的代碼段,它實現了Action的執行。如今咱們就來經過MVC源代碼分析此段代碼所涉及的全部部分。數組
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { private IActionInvoker _actionInvoker; public IActionInvoker ActionInvoker { get { //ActionInvoker的InvokeAction方法就是執行Action的調用。 //可見,此處又有一個擴展點,設置自定義的ActionInvoker(即:在激活Controller後,執行該控制器實例的ActionInvoker屬性,爲屬性賦值便可)。 if (_actionInvoker == null) { _actionInvoker = CreateActionInvoker(); } return _actionInvoker; } set { _actionInvoker = value; } } protected override void ExecuteCore() { PossiblyLoadTempData(); try { //從路由數據中獲取請求的Action的名字(路由系統從請求地址中獲取) string actionName = RouteData.GetRequiredString("action"); //ActionInvoker是Controller類中的一個屬性,該屬性默認返回的是一個AsyncControllerActionInvoker對象 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { PossiblySaveTempData(); } } protected virtual IActionInvoker CreateActionInvoker() {//對於Resolver,只能根據類型反射建立實例,接口和抽象類都是返回null,因此下面的代碼返回的是一個AsyncControllerActionInvoker對象!(MVC3中是直接返回一個ControllerActionInvoker) //AsyncControllerActionInvoker不僅是異步的,他還包括了同步。由於他繼承自ControllerActionInvoker類,並實現了IAsyncActionInvoker接口。 //這裏就有疑問了,既然接口和抽象類都不能建立實例且返回null,那爲何還以接口爲參數呢? return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker(); } }
上述代碼中,紅色字體部分中的ActionInvoker是Controller類的一個屬性,該屬性返回的是私有IActionInvoker類型的字段_actionInvoker的值,若是_actionInvoker不等於null,則返回字段_actionInvoker的值,不然建立一個 AsyncControllerAtionInvoker對象賦值給_actionInvoker字段並返回。因此,在咱們沒有設置自定義ActionInvoker時,默認這個ActionInvoker是一個AsyncControllerActonInvoker對象。即:執行AsyncControllerActonInvoker對象的InvokeAction方法來完成Action的執行!緩存
擴展:此處咱們能夠建立一個自定義的ActionInvoker,而後使用自定義的ActionInvoker來實現Action的執行!
一、建立自定義一個ActionInvoker(實現IActionInvoker接口的類或者直接繼承AsyncControllerActonInvoker類)。
二、建立好自定義的ActionInvoker以後,就須要將咱們的ActionInvoker設置到系統中,就是經過請求的控制器HomeController的基類Controller的這個ActionInvoker屬性來進行設置。因此,咱們就須要在HomeController被激活時,直接執行該控制器實例的ActionInvoker屬性來設置,而控制器的激活是在一個ControllerActivator的Create方法中完成的,ControllerActivator的選擇又是ControllerFactory來作的!cookie
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); ControllerBuilder controllerBulder = ControllerBuilder.Current; controllerBulder.SetControllerFactory(new DefaultControllerFactory(new MyControllerActivator())); }
public class MyControllerActivator:IControllerActivator { public IController Create(System.Web.Routing.RequestContext requestContext, Type controllerType) { Controller con = (Controller)Activator.CreateInstance(controllerType); con.ActionInvoker = new MyActionInvoker(); return con; } }
public class MyActionInvoker : AsyncControllerActionInvoker { public override bool InvokeAction(System.Web.Mvc.ControllerContext controllerContext, string actionName) { //本身來實現Action的執行 } }
上面指出兩部份內容,1、在默認狀況下的ActionInvoker(AsyncControllerActonInvoker);2、使用自定義ActionInvoker。咱們所提到的ActionInvoker都是泛指實現了IActionInvoker接口的類,而上述兩個中狀況【默認ActionInvoker(AsyncControllerActonInvoker)】和【自定義ActionInvoker】即是實現了IActionInvoker接口,並實現了該接口中惟一的一個方法InvokeAction,而實現的這個方法中包含了對Action執行的全部操做,下面就來看看默認狀況下ActionInvoker(AsyncControllerActonInvoker)的InvokeAction方法中是如何定義的!其實,自定義ActionInvoker的InvokeAction方法也是仿照AsyncControllerActonInvoker類來實現的。mvc
public class AsyncControllerActionInvoker : ControllerActionInvoker, IAsyncActionInvoker { //調用父類ControllerActionInvoker中的InvokeAction方法 }
public class ControllerActionInvoker : IActionInvoker { public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { //ControllerDescriptor封裝描述控制器的信息,如控制器的名稱、類型和操做。 ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); //FindAction方法:找到要執行的那麼Action,並將該Action的相關信息封裝在ActionDescriptor中。 ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { //GetFilters方法:獲取應用在Action上的全部過濾器,並封裝到一個FilterInfo對象中。 FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try { //Authorize受權過濾器須要實現IAuthorizationFilter接口,該接口有一個方法:OnAuthorization //循環執行應用在Actio上全部Authorize受權過濾器的OnAuthorization方法,定義若是不知足過濾器條件,則須要建立一個ActionResult複製給Result屬性 //AuthorizeAttribute是MVC封裝好的一個受權過濾器,從Cookie中獲取信息,檢查是否受權成功,可參考定義本身的受權管理器 AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor); if (authContext.Result != null) { //沒有經過Authorize受權過濾器,直接根據自定義的ActionResult進行View的呈現!
//View的呈現(下一節介紹) InvokeActionResult(controllerContext, authContext.Result); } else { //ValidateRequest,該值指示是否爲此請求啓用請求驗證 //是否對請求必須驗證,默認爲true,該屬性定義在ControllerBase類中 if (controllerContext.Controller.ValidateRequest) { //ValidateRequest應該是檢查XSS威脅之類的,在模型綁定請求中獲取值前進行處理。 ValidateRequest(controllerContext); } //獲取Action方法參數的值(模型綁定) IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor); //執行【方法過濾器】(實現IActionFilter接口)並執行Action內代碼 ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); //執行【結果過濾器】(實現IResultFilter接口),再作View的呈現。 InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result); } } catch (ThreadAbortException) { throw; } catch (Exception ex) { //執行異常過濾器 ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex); if (!exceptionContext.ExceptionHandled) { throw; }
//根據異常過濾器中定義的ActionResult進行View的呈現 InvokeActionResult(controllerContext, exceptionContext.Result); } return true; } // notify controller that no method matched return false; } }
上述代碼中已添加了詳細的註釋,大體流程爲:首先,根據【控制器信息】和【Action的Name】從被請求控制器的衆多Action中找到要訪問的Action,而後再執行應用在Action上的過濾器,最後根據ActionResult再進行View的呈現(下一節介紹)。less
擴展:此處ControllerActionInvoker是MVC4中的,MVC5中新添加Authorizetion過濾器,而且這個過濾器的執行模式和Authorizetion過濾器是同樣。對於Authentic過濾器,它須要實現IAuthenticationFilter接口,該接口中有兩個方法:OnAuthentication和OnAuthenticationChallenge,執行順序爲:【Authentic過濾器的OnAuthentication方法】—>【Action過濾器的執行】—>【Action內代碼的執行】—>【Authentic過濾器的OnAuthenticationChallenge方法】—>【Result過濾器的執行】—>【View的呈現】,因此就目前看來,經過這個過濾器也就能夠在Action執行前且View呈現以前進行一些操做,從而可加強擴展性!
異步
public class ControllerActionInvoker : IActionInvoker { public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { //ControllerDescriptor封裝描述控制器的信息,如控制器的名稱、類型和操做。 ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); //FindAction方法:找到要執行的那麼Action,並將其封裝在ActionDescriptor中。 //ActionDescriptor提供有關操做方法的信息,如操做方法的名稱、控制器、參數、特性和篩選器。 ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { //GetFilters方法:獲取應用在Action上的全部過濾器,並封裝到一個FilterInfo對象中。 FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try { //注意:Authentic過濾器須要實現IAuthenticationFilter接口,此接口有兩個方法:OnAuthentication和OnAuthenticationChallenge //循環執行Action上應用的全部Authentic過濾器的OnAuthentication方法,斷定未經過驗證,則建立ActionResult對象給Result屬性(以此來進行View的呈現)。 AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor); //未經過Authentic過濾器的Onauthentication方法 if (authenticationContext.Result != null) { //循環執行全部Authentic過濾器的OnAuthenticationChallenge方法(能夠是任何操做,例:對ActionResult進一步處理等) AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(controllerContext,filterInfo.AuthenticationFilters,AcionDescriptor,authenticationContext.Result); //根據自定義的ActionResult進行View的呈現(沒有經過Authentic過濾器,不需再繼續執行,直接返回結果) InvokeActionResult(controllerContext, challengeContext.Result ?? authenticationContext.Result); } //沒有設置認證器或者認證成功 else { //Authorize受權過濾器須要實現IAuthorizationFilter接口,該接口有一個方法:OnAuthorization //循環執行應用在Actio上全部Authorize受權過濾器的OnAuthorization方法(AuthorizeAttribute是MVC封裝好的一個受權過濾器,從Cookie中獲取信息,檢查是否受權成功,可參考定義本身的受權管理器) AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor); if (authorizationContext.Result != null) { //沒有經過Authorization過濾器,即:OnAuthorization方法中不符合條件 //循環執行Authentica過濾器的OnAuthenticationChallenge方法(能夠是任何操做,例:對ActionResult進一步處理)! AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,authorizationContext.Result); //View的呈現 InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result); } //未設置Authorize過濾器或受權成功 else { //ValidateRequest,該值指示是否爲此請求啓用請求驗證 //是否對請求必須驗證,默認爲true,該屬性定義在ControllerBase類中 if (controllerContext.Controller.ValidateRequest) { //ValidateRequest應該是檢查XSS威脅之類的,在模型綁定請求中獲取值前進行處理。 ValidateRequest(controllerContext); } //獲取Action參數的值(模型綁定) IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor); //執行【方法過濾器】(實現IActionFilter接口)並執行Action內代碼 ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); //再一次循環執行認證過濾器的OnAuthenticationChallenge方法(能夠是任何操做,例:對ActionResult進一步處理)! AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,postActionContext.Result); //執行【結果過濾器】(實現IResultFilter接口),再作View的呈現。 InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters,challengeContext.Result ?? postActionContext.Result); } } } catch (ThreadAbortException) { throw; } catch (Exception ex) { ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex); if (!exceptionContext.ExceptionHandled) { throw; } InvokeActionResult(controllerContext, exceptionContext.Result); } return true; } return false; } }
InvokeAction方法解析ide
一、ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);函數
在控制器HomeController對象的全部方法中,找到當前請求的Action(控制器對象的一個方法)。post
public class ControllerActionInvoker : IActionInvoker { private static readonly ControllerDescriptorCache _staticDescriptorCache = new ControllerDescriptorCache(); private ControllerDescriptorCache _instanceDescriptorCache; internal ControllerDescriptorCache DescriptorCache { get { if (_instanceDescriptorCache == null) { _instanceDescriptorCache = _staticDescriptorCache; } return _instanceDescriptorCache; } set { _instanceDescriptorCache = value; } } public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { //ControllerDescriptor封裝描述控制器的信息,如控制器的名稱、類型和操做。 //此處是controllerDescriptor對象是ControllerDescriptor的派生類ReflectedControllerDescriptor的對象。 ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); //FindAction方法:找到要執行的那麼Action,並將該Action的相關信息封裝在ActionDescriptor中。 ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); //省略其餘代碼 } protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext) { //獲取Controller的類型 Type controllerType = controllerContext.Controller.GetType(); //DescriptorCache是本類的屬性,是一個ControllerDescriptorCache實例。 //GetDescriptor方法的本質是根據controllerType去緩存中獲取,若是沒有的話,就執行委託(第二個參數)去建立,並作爲返回值。再添加到緩存字典表中,以便下次利用。 //以下,沒有緩存的狀況下,就執行委託建立一個ReflectedControllerDescriptor對象。即:能夠看出全部的ControllerDescriptor都是一個ReflectedControllerDescriptor。 ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(controllerType, () => new ReflectedControllerDescriptor(controllerType)); //返回這個繼承自ControllerDescriptor的ReflectedControllerDescriptor對象。 return controllerDescriptor; } protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) { //執行參數controllerDescriptor(ReflectedControllerDescriptor對象)的FindAction方法 ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); return actionDescriptor; } }
public class ReflectedControllerDescriptor : ControllerDescriptor { private readonly Type _controllerType; private readonly ActionMethodSelector _selector; //構造函數 public ReflectedControllerDescriptor(Type controllerType) { if (controllerType == null) { throw new ArgumentNullException("controllerType"); } _controllerType = controllerType; _selector = new ActionMethodSelector(_controllerType); } public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (String.IsNullOrEmpty(actionName)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName"); } //_selector.FindActionMethod方法,先根據類型找到他的全部方法,而後根據方法名字再去匹配。 //_selector是在該類的構造函數中建立的ActionMethodSelector對象。 //獲取指定的Action MethodInfo matched = _selector.FindActionMethod(controllerContext, actionName); if (matched == null) { return null; } //將找到的那個Action封裝到一個ReflectedActionDescriptor對象(即:ActionDescriptor的派生類)中。 return new ReflectedActionDescriptor(matched, actionName, this); } }
internal sealed class ActionMethodSelector { //構造函數 public ActionMethodSelector(Type controllerType) { ControllerType = controllerType; //獲取控制HomeController的全部方法 PopulateLookupTables(); } public Type ControllerType { get; private set; } public MethodInfo[] AliasedMethods { get; private set; } public ILookup<string, MethodInfo> NonAliasedMethods { get; private set; } private AmbiguousMatchException CreateAmbiguousMatchException(List<MethodInfo> ambiguousMethods, string actionName) { StringBuilder exceptionMessageBuilder = new StringBuilder(); foreach (MethodInfo methodInfo in ambiguousMethods) { string controllerAction = Convert.ToString(methodInfo, CultureInfo.CurrentCulture); string controllerType = methodInfo.DeclaringType.FullName; exceptionMessageBuilder.AppendLine(); exceptionMessageBuilder.AppendFormat(CultureInfo.CurrentCulture, MvcResources.ActionMethodSelector_AmbiguousMatchType, controllerAction, controllerType); } string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ActionMethodSelector_AmbiguousMatch, actionName, ControllerType.Name, exceptionMessageBuilder); return new AmbiguousMatchException(message); } public MethodInfo FindActionMethod(ControllerContext controllerContext, string actionName) { //對應用了ActionNameSelectorAttribute特性的Action方法集合處理,獲取方法名字是actionName的全部Action方法。 List<MethodInfo> methodsMatchingName = GetMatchingAliasedMethods(controllerContext, actionName); //對沒有應用ActionNameSelectorAttribute特性的Action方法集合處理,獲取方法名字是actionName的全部方法,並添加集合尾部。 methodsMatchingName.AddRange(NonAliasedMethods[actionName]); //目前爲止,methodsMatchingName集合中保存的是HomeController中Action方法的名字等於actionName的方法 //再作一次篩選和處理,處理Action方法上應用了NonAction、AcceptVerbs、HttpGet、HttpPost、HttpDelete、HttpPut特性狀況 List<MethodInfo> finalMethods = RunSelectionFilters(controllerContext, methodsMatchingName); //只有符合條件的Action方法僅有一個時,才返回。(這就是爲什麼,當咱們定義兩個方法名相同且參數不一樣且又都應用HttpGet特性時,會報錯) switch (finalMethods.Count) { case 0: return null; case 1: return finalMethods[0]; default: throw CreateAmbiguousMatchException(finalMethods, actionName); } } internal List<MethodInfo> GetMatchingAliasedMethods(ControllerContext controllerContext, string actionName) { //有一個緩存,保存Action方法的ActionName特性。 //ReflectedAttributeCache.GetActionNameSelectorAttributes(methodInfo)根據methodInfo去緩存表中找,若是沒有的話,就利用methodInfo的GetCustomAttributes方法去獲取ActionName屬性(一個ActionNameAttribute對象)。 //遍歷全部應用了ActionName特性的方法,並篩選獲得特性的名字=當前請求的action名稱 //ActionNameAttribute的IsValidName方法,就是根據String.Equals(actionName, Name, StringComparison.OrdinalIgnoreCase)判斷的 var methods = from methodInfo in AliasedMethods let attrs = ReflectedAttributeCache.GetActionNameSelectorAttributes(methodInfo) where attrs.All(attr => attr.IsValidName(controllerContext, actionName, methodInfo)) select methodInfo; return methods.ToList(); } private static bool IsMethodDecoratedWithAliasingAttribute(MethodInfo methodInfo) { //在派生類中重寫時,指示是否 attributeType 的一個或多個實例應用於此成員。 //第二個參數:指定是否搜索該ActionNameSelectorAttribute的繼承鏈以查找這些特性。 //返回若是 (ActionNameSelectorAttribute) 的一個或多個實例應用於此成員(包括特性基類),則爲 true;不然爲 false。 //也就是該Action上應用了ActionName特性來實現一個別名 return methodInfo.IsDefined(typeof(ActionNameSelectorAttribute), true /* inherit */); } private static bool IsValidActionMethod(MethodInfo methodInfo) { //獲取定義在自定義的Controller(HomeController)中的方法。過濾掉Controller類中的方法和Controller類的基類中的方法。 //IsSpecialName表示方法是否具備特殊名稱。(若是是HomeController中本身寫得方法,則返回false,若是是Controller類或其基類中的方法時,返回true) //GetBaseDefinition方法獲得該methodInfo被第一次定義的方法,(咱們寫的Action都是第一次定義在HomeControlelr中,若是在自定格的HomeController中重寫基類中的方法,則這個GetBaseDefinition方法獲得的就是第一次被建立的那個方法-多是接口中定義的方法,) //DeclaringType屬性獲取該方法所在的類 //IsAssignableFrom(typeof(Controller)方法,檢查是否該類型能夠從Controller的實例分配。 //若是methodInfo.GetBaseDefinition().DeclaringType獲得的 type類型 是Controller類或Controller的基類或Controller實現的接口,則返回true return !(methodInfo.IsSpecialName || methodInfo.GetBaseDefinition().DeclaringType.IsAssignableFrom(typeof(Controller))); } private void PopulateLookupTables() { //反射獲得控制器HomeController的全部方法,包括繼承自基類的全部方法 MethodInfo[] allMethods = ControllerType.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public); //篩選,獲取在控制器HomeController中建立的Action方法(依據:循環全部方法,方法是否可利用Controller類實例獲得) MethodInfo[] actionMethods = Array.FindAll(allMethods, IsValidActionMethod); //篩選,獲取HomeConroller中應用了ActionNameSelectorAttribute特性的Action方法。(ActionName特性的目的就是爲Action設置一個別名) AliasedMethods = Array.FindAll(actionMethods, IsMethodDecoratedWithAliasingAttribute); //篩選,獲取HomeController中除去應用了ActionName特性的方法以外的全部方法。(只要應用了ActionName特性的方法都不在這個集合內) NonAliasedMethods = actionMethods.Except(AliasedMethods).ToLookup(method => method.Name, StringComparer.OrdinalIgnoreCase); } private static List<MethodInfo> RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos) { //局部變量,保存應用了NonAction、AcceptVerbs、HttpGet、HttpPost、HttpDelete、HttpPut特性的Action方法(也能夠叫作選擇特性) List<MethodInfo> matchesWithSelectionAttributes = new List<MethodInfo>(); ////局部變量,保存應用了NonAction、AcceptVerbs、HttpGet、HttpPost、HttpDelete、HttpPut特性的Action方法 List<MethodInfo> matchesWithoutSelectionAttributes = new List<MethodInfo>(); foreach (MethodInfo methodInfo in methodInfos) { //從緩存中根據methodInfo獲取【選擇特性】,若是緩存中沒有的話,就主動去獲取方法的全部特性中【選擇特性】,並添加到緩存表中。 //ActionName特性類繼承自ActionNameSelectorAttribute類 //NonAction、AcceptVerbs、HttpGet、HttpPost、HttpDelete、HttpPut特性類都繼承自ActionMethodSelectorAttribute類。 ICollection<ActionMethodSelectorAttribute> attrs = ReflectedAttributeCache.GetActionMethodSelectorAttributes(methodInfo); if (attrs.Count == 0) { //若是Action方法上沒有應用【選擇特性】 matchesWithoutSelectionAttributes.Add(methodInfo); } //檢查方法上定義的選擇特性 是否 和客戶端使用的 HTTP 數據傳輸方法一致 //調用應用在方法上的特性的IsValidForRequest方法。(只有那6個繼承自ActionMethodSelectorAttribute類的特性,由於IsValidForRequest最開始是在此類中定義抽象方法) //對於NonAction特性,IsValidForRequest方法直接返回false //All方法:全部元素所有經過則返回true,不然返回false else if (attrs.All(attr => attr.IsValidForRequest(controllerContext, methodInfo))) { //特性經過驗證,也就是和客戶端使用的http數據傳輸方法一直 matchesWithSelectionAttributes.Add(methodInfo); } } //若是Action方法上存在應用了【選擇特性】且又經過了驗證,則返回應用了【選擇特性】的Action方法集合, //當【選擇特性】都未經過驗證時,則返回沒有應用【選擇特性】的Action方法集合(即:Action上沒有HttpGet、HttpPost等特性的方法) //此處說明了Action方法執行的優先級:應用了正確的HttpGet、HttpPost等特性的Action方法優先於未應用HttpGet、HttpPost等特性的Action方法 return (matchesWithSelectionAttributes.Count > 0) ? matchesWithSelectionAttributes : matchesWithoutSelectionAttributes; } } ActionMethodSelector
上述代碼中,其實就是經過HomeController實例利用反射獲取到全部的方法(包括父類中的方法),而後就是進行篩選,首先經過判斷獲得的方法是不是Controller類實例的方法,從而將HomeController父類中的方法過濾掉;以後再根據方法的名字來作判斷,從而將方法名字不是請求的actionName的方法過濾掉;再以後判斷應用在Action方法上的特性是否和客戶端使用的 HTTP 數據傳輸方法一致,將不符合Http數據傳輸方法的Action過濾掉;再再以後,當符合條件的Action方法只有一個時,就將該Action方法返回,即:獲得了指定的Action。最後將獲得的Action方法封裝到一個繼承自ActionDescriptor類的ReflectedActionDescriptor對象中。
擴展:由上面介紹可知,其實對Action方法的查找和篩選都是在ActionMethodSelector中進行的,MVC5中的ActionMethodSelector雖然大致上流程是和MVC4相同的,可是具體實現上仍是有點差別,有興趣的能夠看一下。
internal sealed class ActionMethodSelector { public ActionMethodSelector(Type controllerType) { ControllerType = controllerType; PopulateLookupTables(); } public Type ControllerType { get; private set; } public MethodInfo[] AliasedMethods { get; private set; } public ILookup<string, MethodInfo> NonAliasedMethods { get; private set; } private AmbiguousMatchException CreateAmbiguousMatchException(List<MethodInfo> ambiguousMethods, string actionName) { StringBuilder exceptionMessageBuilder = new StringBuilder(); foreach (MethodInfo methodInfo in ambiguousMethods) { string controllerAction = Convert.ToString(methodInfo, CultureInfo.CurrentCulture); string controllerType = methodInfo.DeclaringType.FullName; exceptionMessageBuilder.AppendLine(); exceptionMessageBuilder.AppendFormat(CultureInfo.CurrentCulture, MvcResources.ActionMethodSelector_AmbiguousMatchType, controllerAction, controllerType); } string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ActionMethodSelector_AmbiguousMatch, actionName, ControllerType.Name, exceptionMessageBuilder); return new AmbiguousMatchException(message); } public MethodInfo FindActionMethod(ControllerContext controllerContext, string actionName) { //斷言,成功時什麼也不作 Contract.Assert(controllerContext != null); if (controllerContext.RouteData != null) { //尼瑪,RouteData的這個GetTargetActionMethod方法在那裏呀? MethodInfo target = controllerContext.RouteData.GetTargetActionMethod(); if (target != null) { // short circuit the selection process if a direct route was matched. return target; } } //獲得全部知足要求的Action,(包括應用了ActionName特性和原Action的名字和請求的Action相同的) List<MethodInfo> finalMethods = FindActionMethods(controllerContext, actionName, AliasedMethods, NonAliasedMethods); //只有當HomeController中的Action有且只有一個知足請求的,才返回。因此,Controller中不容許Action重複(參數不一樣能夠) switch (finalMethods.Count) { case 0: return null; //只有裏面有一個合適的Action時才正確返回。 case 1: return finalMethods[0]; default: throw CreateAmbiguousMatchException(finalMethods, actionName); } } internal static List<MethodInfo> FindActionMethods(ControllerContext controllerContext, string actionName, MethodInfo[] aliasedMethods, ILookup<string, MethodInfo> nonAliasedMethods) { List<MethodInfo> matches = new List<MethodInfo>(); //遍歷全部應用了ActionName屬性的全部方法。 for (int i = 0; i < aliasedMethods.Length; i++) { MethodInfo method = aliasedMethods[i]; //IsMatchingAliasedMethod方法獲取Action上應用的ActionName屬性的值,並將該值和請求的Action相比較,若是一致則直接添加到列表。 if (IsMatchingAliasedMethod(method, controllerContext, actionName)) { matches.Add(method); } } matches.AddRange(nonAliasedMethods[actionName]);//將全部方法再添加到集合matches的末尾(最後獲取Action的時候,是獲取索引的第一個。這就是爲何ActionName特性優先於原Action的名字) //到如今爲止,集合matches中剩下只有和請求的Action相同的 方法(包含Action、應用了ActionName才符合的Action、普通方法)了 RunSelectionFilters(controllerContext, matches);//篩選Controller中定義的因此方法,是否爲Aciton,若是不是,則移除 return matches; } private static bool IsMatchingAliasedMethod(MethodInfo method, ControllerContext controllerContext, string actionName) { //又一個緩存,若是緩存表中沒有的話,緩存着Action的ActionName特性(每一個Action只能使用一個ActionName屬性,這裏爲何是個集合呢?不明白)。 //ReflectedAttributeCache.GetActionNameSelectorAttributes(method)根據method去緩存表中找,若是沒有的話,就利用method的GetCustomAttributes方法去獲取ActionName屬性(一個ActionNameAttribute對象)。 //獲取方法上應用了 繼承了ActionNameSelectorAttribute 類的特性! //只有ActionNameAttribute繼承自ActionNameSelectorAttribute類 ReadOnlyCollection<ActionNameSelectorAttribute> attributes = ReflectedAttributeCache.GetActionNameSelectorAttributes(method); // Caching count is faster for ReadOnlyCollection int attributeCount = attributes.Count; //遍歷每一個ActionName屬性,即ActionNameAttribute對象(在Action上應用該特性時就實例化了ActionNameAttribute,且構造函數的參數就是:Action上定義的Action的別名)。 for (int i = 0; i < attributeCount; i++) { //判斷特性中設置別名和請求的Action是否一致。 //ActionNameSelectorAttribute是抽象類,ActionNameAttribute實現IsValidName方法,就是根據名字的String.Equals(actionName, Name, StringComparison.OrdinalIgnoreCase); if (!attributes[i].IsValidName(controllerContext, actionName, method)) { return false; } } return true; } private static bool IsValidMethodSelector(ReadOnlyCollection<ActionMethodSelectorAttribute> attributes, ControllerContext controllerContext, MethodInfo method) { int attributeCount = attributes.Count; Contract.Assert(attributeCount > 0); for (int i = 0; i < attributeCount; i++) { //調用應用在方法上的特性的IsValidForRequest方法。(只有那6個繼承自ActionMethodSelectorAttribute類的特性,由於IsValidForRequest最開始是在此類中定義抽象方法) //NonAction特性,IsValidForRequest方法直接返回false,括號內就是true,整個方法返回 false //AcceptVerbs特性,應用時,AcceptVerbsAttribute構造函數傳入的HttpVerbs類型(枚舉,有Get、Post、Put、Delete、Head)的參數,並在構造函數內以此參數爲參數又建立了一個HttpVerbsValidator實例,HttpVerbsValidator的構造函數中,將httpverbs參數存入到私有的集合變量中,而AcceptVerbs特性的IsValidForRequest方法,內部本質上執行的是HttpVerbsValidator實例的IsValidForRequest方法,這個方法就是檢查 保存HttpVerbs的私有變量集合中 是否含有發來的請求的HttpVerbs //其實,AcceptVerbs特性和這些HttpGet、HttpPost、HttpPut、HttpDelete同樣,只不過其多了一個Head,這個是什麼呢? //HttpGet特性,HttpGetAttribute繼承自HttpVerbAttribut。執行HttpGetAttribute構造函數時,執行HttpVerbAttribut構造函數並直接給一個參數(HttpVerbs.HttpGet),其構造函數內部也是建立一個參數爲HttpGet的HttpVerbsValidator實例,以後同上... //HttpPost特性,和HttpGet同樣,只不過傳入的HttpVerbAttribut構造函數的參數爲HttpVerbs.Post //HttpDelete特性,同上 //HttpPut特性,同上 //其實就是 檢查方法上定義的特性 是否 和客戶端使用的 HTTP 數據傳輸方法一致。 //若是一致,則返回 true,括號內爲false,整個方法返回true //若是不一致,則返回 false,括號內爲true,整個方法返回false if (!attributes[i].IsValidForRequest(controllerContext, method)) { return false; } } return true; } private static bool IsMethodDecoratedWithAliasingAttribute(MethodInfo methodInfo) { //在派生類中重寫時,指示是否 attributeType 的一個或多個實例應用於此成員。 //第二個參數:指定是否搜索該ActionNameSelectorAttribute的繼承鏈以查找這些特性。 //返回若是 (ActionNameSelectorAttribute) 的一個或多個實例應用於此成員(包括特性基類),則爲 true;不然爲 false。 //也就是該Action上應用了ActionName特性來實現一個別名 return methodInfo.IsDefined(typeof(ActionNameSelectorAttribute), true /* inherit */); } //獲取定義在自定義的Controller(HomeController)中的方法。過濾掉Controller類中的方法和Controller類的基類中的方法。 private static bool IsValidActionMethod(MethodInfo methodInfo) { //IsSpecialName表示方法是否具備特殊名稱。(若是是HomeController中本身寫得方法,則返回false,若是是Controller類或其基類中的方法時,返回true) //GetBaseDefinition方法獲得該methodInfo被第一次定義的方法,(咱們寫的Action都是第一次定義在HomeControlelr中,若是在自定格的HomeController中重寫基類中的方法,則這個GetBaseDefinition方法獲得的就是第一次被建立的那個方法-多是接口中定義的方法,) //DeclaringType屬性獲取該方法所在的類 //IsAssignableFrom(typeof(Controller)方法,檢查是否該類型能夠從Controller的實例分配。 //若是methodInfo.GetBaseDefinition().DeclaringType獲得的 type類型 是Controller類或Controller的基類或Controller實現的接口,則返回true return !(methodInfo.IsSpecialName || methodInfo.GetBaseDefinition().DeclaringType.IsAssignableFrom(typeof(Controller))); } private void PopulateLookupTables() { //根據類型反射全部方法,包括繼承自基類的全部方法 MethodInfo[] allMethods = ControllerType.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public); //篩選,獲得自定義在Controller中添加的方法。 //Array的FindAll方法,第二個參數是一個委託 MethodInfo[] actionMethods = Array.FindAll(allMethods, IsValidActionMethod); //集合、篩選邏輯(委託) //篩選,獲取應用了ActionNameSelectorAttribute特性的Action。ActionName特性的目的就是爲Action設置一個別名 AliasedMethods = Array.FindAll(actionMethods, IsMethodDecoratedWithAliasingAttribute); //錯誤=篩選,獲取全部的方法(不含別名,可是有有別名的Action的原名在內),而且根據方法名進行分組,且方法名不區分大小寫。(Action名字相同,參數不一樣則分在一組) //正確=上述理解錯誤,這裏獲取的是除去了應用了ActionName特性的方法以外的全部方法。(只要應用了ActionName特性的方法都不在這個集合內) NonAliasedMethods = actionMethods.Except(AliasedMethods).ToLookup(method => method.Name, StringComparer.OrdinalIgnoreCase); } //最後的篩選 private static void RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos) { //到如今爲止,集合methodInfos中剩下只有和請求的Action相同的 方法(包含:原名符合的Action、應用了ActionName才符合的Action、普通方法)了 bool hasValidSelectionAttributes = false; //遍歷目前符合條件的全部方法 for (int i = methodInfos.Count - 1; i >= 0; i--) { MethodInfo methodInfo = methodInfos[i]; //獲取方法集合中,是Action的方法。 //若是應用了NonAction特性,attrs.Count=1; //若是應用了HttpPut特性,attrs.Count=1 //若是應用了HttpDelete特性,attrs.Count=1 //若是應用了HttpPost特性,attrs.Count=1 //若是應用了HttpGet特性,attrs.Count=1 //若是應用了ccetpVerbs特性,attrs.Count=1A //以上的特性若是共同應用在方法上,那麼attrs.Count=2.3.4.5.6.7.8.9... //若是是應用了ActionName特性才符合的Action,這裏attrs.Count=0。ActionName繼承自ActionNameSelectorAttribute==== 咱們稱之爲 名稱特性 //只要沒有應用以上特性,不管是定義的Action仍是普通方法 均爲:atters.count=0,即:符合要求 //其實就是獲取方法上應用的全部特性(特性是ActionMethodSelectorAttribute類的派生類,咱們稱之爲方法特性)。 //也只有以上6個特性繼承自ActionMethodSelectorAttribute類。(只有ActionNameAttribute繼承自ActionNameSelectorAttribute類) ReadOnlyCollection<ActionMethodSelectorAttribute> attrs = ReflectedAttributeCache.GetActionMethodSelectorAttributesCollection(methodInfo); //若是該方法上沒有應用方法特性 if (attrs.Count == 0) { // case 1: this method does not have a MethodSelectionAttribute //第一次進來時hasValidSelectionAttributes是false,不作操做,故:沒有應用NonAction特性的方法就經過了。 if (hasValidSelectionAttributes) { // if there is already method with a valid selection attribute, remove method without one methodInfos.RemoveAt(i); } } //其實就是 檢查方法上定義的特性 是否 和客戶端使用的 HTTP 數據傳輸方法一致。 //若是一致,則返回true //若是不一致,則返回false else if (IsValidMethodSelector(attrs, controllerContext, methodInfo)) { //客戶端使用的Http數據傳輸方式和 定義在Action上的特性設置的一致 if (!hasValidSelectionAttributes) //第一次時,true 可進入 { //符合條件的Action集合中, //只有第一個進入到這裏(應用了方法特性且Http傳輸方式一致)或不符合的已刪除當前索引位於頂層,不符合i + 1 < methodInfos.Count //當前索引不位於集合的頂層(即:已經有符合條件的Action存在), if (i + 1 < methodInfos.Count) { //猜想:是將當前索引上層的全部項都移除(即已經篩選出的符合的Action都移除--沒有應用特性的)。 //猜測正確,此RemoveFrom是MVC寫的一個List<T>的擴展方法,MVC源碼的目錄 .\src\Common\ 的CollectionExtensions.cs類中 methodInfos.RemoveFrom(i + 1); } //將這個標識設置爲true。 //當下次循環的Action沒有應用ActionMethodSelectorAttribute特性時,移除。=======因此,應用了ActionMethodSelectorAttribute特性的Action比沒有應用的優先級要高!(例:定義兩個Action,其中一個應用HttpGet,應用了的優先級高) //當下次循環的Action應用了ActionMethodSelectorAttribute特性,而且和客戶端使用的傳輸方法一致。直接經過... 這就是當定義兩個Action,都設置爲HttpGet,就會出現:【對控制器類型「HomeController」的操做「Index」的當前請求在下列操做方法之間不明確:】 hasValidSelectionAttributes = true; } } //應用數據傳輸方法特性,可是請求和Action上設置的不一致。移除該Action else { methodInfos.RemoveAt(i); } } } }
二、FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
獲取應用在Action方法上的全部過濾器,並將封裝到一個FilterInfo對象中。這些過濾器有:ActionFilter、AuthorizationFilter、ExceptionFilter、ResultFilter,另外在MVC5中又新添加了一個AuthenticationFilter過濾器。
public class ControllerActionInvoker : IActionInvoker { private static readonly ControllerDescriptorCache _staticDescriptorCache = new ControllerDescriptorCache(); //FilterProviders.Providers.GetFilters是有兩個參數的方法,該方法就是去獲取並篩選過濾器 //IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = FilterProviders.Providers.GetFilters; public ControllerActionInvoker() { } protected virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return new FilterInfo(_getFiltersThunk(controllerContext, actionDescriptor)); } public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { //過去應用在Action方法上的全部過濾器 FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); //省略其餘代碼 } } }
public static class FilterProviders { //靜態構造函數 static FilterProviders() { //FilterProviderCollection繼承自Collection<IFilterProvider>類 //實例化FilterProviderCollection時,會先實例化其父類。Collection<IFilterProvider>實例化時,會建立一個List<IFilterProvider>對象items做爲私有變量。 Providers = new FilterProviderCollection(); //Add方法定義在Collection<IFilterProvider>中,就是將參數添加到私有變量 items 中。 Providers.Add(GlobalFilters.Filters); //GlobalFilters.Filters屬性的值其實就是 new GlobalFilterCollection(); Providers.Add(new FilterAttributeFilterProvider()); Providers.Add(new ControllerInstanceFilterProvider()); } public static FilterProviderCollection Providers { get; private set; } }
public class FilterProviderCollection : Collection<IFilterProvider> { private static FilterComparer _filterComparer = new FilterComparer(); private IResolver<IEnumerable<IFilterProvider>> _serviceResolver; public FilterProviderCollection() { //Items是父類Collection<IFilterProvider>中的一個屬性,該屬性獲得已添加到該集合中的全部【過濾器】的【提供器】 //將【過濾器】的【提供器】集合和一個空的Objcect類型集合IEnumerable<object>鏈接並複製到MultiServiceResolver類中的一個字段中 //以後MultiServiceResolver對象的Current屬性就是獲取該集合 _serviceResolver = new MultiServiceResolver<IFilterProvider>(() => Items); } public FilterProviderCollection(IList<IFilterProvider> providers) : base(providers) { _serviceResolver = new MultiServiceResolver<IFilterProvider>(() => Items); } internal FilterProviderCollection(IResolver<IEnumerable<IFilterProvider>> serviceResolver, params IFilterProvider[] providers) : base(providers) { _serviceResolver = serviceResolver ?? new MultiServiceResolver<IFilterProvider>(() => Items); } private IEnumerable<IFilterProvider> CombinedItems { //獲取【過濾器】的【提供器】集合 get { return _serviceResolver.Current; } } private static bool AllowMultiple(object filterInstance) { IMvcFilter mvcFilter = filterInstance as IMvcFilter; //過濾器沒有直接或間接的實現IMvcFilter接口,FilterAttribute類實現了IMvcFilter接口,也就是說該過濾器是一個普通特性。 if (mvcFilter == null) { return true; } return mvcFilter.AllowMultiple; } public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (actionDescriptor == null) { throw new ArgumentNullException("actionDescriptor"); } //遍歷【過濾器】的【提供器】,也就是在實例化FilterProviders時候添加的那 3 個對象 【GlobalFilters.Filters(也就是new GlobalFilterCollection())】、【new FilterAttributeFilterProvider()】、【new ControllerInstanceFilterProvider()】 //執行各【提供器】對象的GetFilters方法,獲取相應的過濾器,並根據Scope值排序,最後將過濾器添加到combineFilters集合中 //全局過濾器:Global = 10 //Controller上應用的過濾器:Controller = 20, //Action上應用的過濾:Action=30 //其實,控制器自己也是一個過濾器:First=0 IEnumerable<Filter> combinedFilters = CombinedItems.SelectMany(fp => fp.GetFilters(controllerContext, actionDescriptor)) .OrderBy(filter => filter, _filterComparer); //移除重複的過濾器,容許重複的過濾器不作移除,即:應用了AllowMultiple=true的過濾器即便重複也不移除 //combinedFilters.Reverse()將集合次序倒轉去執行移除,從而使得添加過濾器的位置不一樣優先級也不一樣。 //即:若是過濾器沒有定義AllowMultiple屬性,則只保留Scope值大的過濾器。 //若是定義AllowMultiple=true,那麼就先執行Scope值小的,再執行Scope值大的過濾器。 return RemoveDuplicates(combinedFilters.Reverse()).Reverse(); } private IEnumerable<Filter> RemoveDuplicates(IEnumerable<Filter> filters) { HashSet<Type> visitedTypes = new HashSet<Type>(); //從後向前循環全部的過濾器 foreach (Filter filter in filters) { object filterInstance = filter.Instance; Type filterInstanceType = filterInstance.GetType(); //visitedTypes集合中不包含該過濾器 //AllowMultiple方法:該過濾器若是沒有繼承FilterAttribute類(該類實現了IMvcFilter接口),返回true;不然返回該過濾器的AllowMultiple屬性(默認爲false)。 //即:visitedTypes集合中不包含該過濾器,添加 // 使用過濾器時定義AllowMultiple屬性爲true時,添加 // 該過濾器沒有實現IMvcFilter接口,則添加;指的是該特性不是MVC過濾器,即:應用的普通特性,而不是MVC過濾器 if (!visitedTypes.Contains(filterInstanceType) || AllowMultiple(filterInstance)) { yield return filter; visitedTypes.Add(filterInstanceType); } } } private class FilterComparer : IComparer<Filter> { public int Compare(Filter x, Filter y) { // Nulls always have to be less than non-nulls if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } // Sort first by order... if (x.Order < y.Order) { return -1; } if (x.Order > y.Order) { return 1; } // ...then by scope if (x.Scope < y.Scope) { return -1; } if (x.Scope > y.Scope) { return 1; } return 0; } } }
internal class MultiServiceResolver<TService> : IResolver<IEnumerable<TService>> where TService : class { private Lazy<IEnumerable<TService>> _itemsFromService; private Func<IEnumerable<TService>> _itemsThunk; private Func<IDependencyResolver> _resolverThunk; //過濾器時TService=IFilterProvider public MultiServiceResolver(Func<IEnumerable<TService>> itemsThunk) { if (itemsThunk == null) { throw new ArgumentNullException("itemsThunk"); } _itemsThunk = itemsThunk; _resolverThunk = () => DependencyResolver.Current; //resolver.GetServices<TService>()方法是反射獲取實例對象,此處內部執行的是 return Enumerable.Empty<object>(); 也就返回了一個空的Objcect類型集合IEnumerable<object> _itemsFromService = new Lazy<IEnumerable<TService>>(() => _resolverThunk().GetServices<TService>()); } internal MultiServiceResolver(Func<IEnumerable<TService>> itemsThunk, IDependencyResolver resolver) : this(itemsThunk) { if (resolver != null) { _resolverThunk = () => resolver; } } public IEnumerable<TService> Current { //Concat方法鏈接兩個序列,是將 【空的IEnumerable<TService>集合】和【原來添加的過濾器提供器的集合】鏈接起來,並轉換爲數組類型。(其實仍是【過濾器提供器的集合】) get { return _itemsFromService.Value.Concat(_itemsThunk()); } } }
public sealed class GlobalFilterCollection : IEnumerable<Filter>, IFilterProvider { private List<Filter> _filters = new List<Filter>(); public int Count { get { return _filters.Count; } } public void Add(object filter) { AddInternal(filter, order: null); } public void Add(object filter, int order) { AddInternal(filter, order); } private void AddInternal(object filter, int? order) { ValidateFilterInstance(filter); //將過濾器添加到集合中 _filters.Add(new Filter(filter, FilterScope.Global, order)); } public void Clear() { _filters.Clear(); } public bool Contains(object filter) { return _filters.Any(f => f.Instance == filter); } public IEnumerator<Filter> GetEnumerator() { return _filters.GetEnumerator(); } //這個的目的是,當將實現了IEnumerable接口的類型的對象 轉換爲IEnumerable接口才能執行該方法 //在GlobalFilterCollection中聲明瞭一個只有將對象轉換爲指定類型IEnumerable才能夠訪問的方法! IEnumerator IEnumerable.GetEnumerator() { return _filters.GetEnumerator(); } //IFilterProvider.GetFilters的目的是,只有將GlobalFilterCollection實例轉換爲IFilterProvider接口類型後才能執行該方法。 //在GlobalFilterCollection中聲明瞭一個只有將對象轉換爲指定類型IFilterProvider才能夠訪問的方法! IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { //將本類的當前對象返回。 //由於這個類實現了IEnumerable<Filter>接口。也完成了迭代器的重寫(上面的兩個方法中_filters.GetEnumerator()),因此Foreach才能遍歷_filters變量中的值。 return this; } public void Remove(object filter) { _filters.RemoveAll(f => f.Instance == filter); } private static void ValidateFilterInstance(object instance) { if (instance != null && !( instance is IActionFilter || instance is IAuthorizationFilter || instance is IExceptionFilter || instance is IResultFilter || instance is IAuthenticationFilter)) { throw new InvalidOperationException(MvcResources.GlobalFilterCollection_UnsupportedFilterInstance); } } }
public class FilterAttributeFilterProvider : IFilterProvider { //構造函數中設置爲true private readonly bool _cacheAttributeInstances; public FilterAttributeFilterProvider() : this(true) { } public FilterAttributeFilterProvider(bool cacheAttributeInstances) { _cacheAttributeInstances = cacheAttributeInstances; } protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { //經過Action描述(封裝了當前的Action的信息),獲取應用在Action上的過濾器 return actionDescriptor.GetFilterAttributes(_cacheAttributeInstances); } protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { //根據Action描述先獲取Controller描述(封裝了當前的Controller的信息), return actionDescriptor.ControllerDescriptor.GetFilterAttributes(_cacheAttributeInstances); } //yield關鍵字,當遍歷此方法GetFilters的返回值IEnumerable<Filter>時,只有循環到來時才執行一次return,延遲執行。(實際上是實現每次循環值返回一個Filter對象。而不是一個Filter集合) public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { // Results are low in number in the common case so use yield return to avoid creating intermediate collections or nested enumerables if (controllerContext.Controller != null) { //遍歷獲取應用在Controller上的過濾器 //先執行GetControllerAttributes方法,獲取全部應用在Controller上的過濾器。(直接所有獲得) //而後根據過濾器建立Filter對象。 foreach (FilterAttribute attr in GetControllerAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr, FilterScope.Controller, order: null); } //遍歷獲取應用在Action上的過濾器 foreach (FilterAttribute attr in GetActionAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr, FilterScope.Action, order: null); } } } }
public class ControllerInstanceFilterProvider : IFilterProvider { public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext.Controller != null) { // Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue); } } }
public class FilterInfo { private List<IActionFilter> _actionFilters = new List<IActionFilter>(); private List<IAuthorizationFilter> _authorizationFilters = new List<IAuthorizationFilter>(); private List<IExceptionFilter> _exceptionFilters = new List<IExceptionFilter>(); private List<IResultFilter> _resultFilters = new List<IResultFilter>(); public FilterInfo() { } public FilterInfo(IEnumerable<Filter> filters) { // evaluate the 'filters' enumerable only once since the operation can be quite expensive var filterInstances = filters.Select(f => f.Instance).ToList(); _actionFilters.AddRange(filterInstances.OfType<IActionFilter>()); _authorizationFilters.AddRange(filterInstances.OfType<IAuthorizationFilter>()); _exceptionFilters.AddRange(filterInstances.OfType<IExceptionFilter>()); _resultFilters.AddRange(filterInstances.OfType<IResultFilter>()); } public IList<IActionFilter> ActionFilters { get { return _actionFilters; } } public IList<IAuthorizationFilter> AuthorizationFilters { get { return _authorizationFilters; } } public IList<IExceptionFilter> ExceptionFilters { get { return _exceptionFilters; } } public IList<IResultFilter> ResultFilters { get { return _resultFilters; } } }
上述代碼中,實現了獲取過濾器,而過濾器能夠經過4種方式添加:一、Global.asax中的RegisterGlobalFilters方法,Scope=10;二、在控制器HomeController上以特性的方法添加,Scope=20;三、在Action上以特性的方式添加,Scope=30;四、控制器HomeController自己也是過濾器,它實現了各過濾器接口,Scope=0;
針對以上的4中添加方法,【1】直接經過GlobalFilterCollection集合來獲取,應爲GlobalFilterCollection實現了IEnumerable接口、【2】【3】經過FilterAttributeFilterProvider對象的GetFilters方法來獲取、【4】經過ControllerInstanceFilterProvider對象的GetFilters方法來獲取。
因此,整個流程爲:遍歷執行各【過濾器的提供器】的GetFilters方法,從而獲得全部過濾器且過濾器按照Scope值從小到大排列,而後再從後向前執行來對不容許重複使用的過濾器進行去重(只保留Scope值大的過濾器),若是容許重複使用的話(AllowMutiple=true),表示容許重複使用該過濾器,則不執行去重。最終將獲得的過濾器按照過濾器類型(按接口不一樣)分類封裝到FilterInfo對象中。
更正:FilterProviderCollection類的AllowMultiple方法中【if(mvcFilter==null){true}】,也表示該過濾器爲控制器自己。由於Controller類只實現了過濾器接口,而沒有實現IMvcFilter接口或繼承實現了IMvcFilter接口的類。
擴展:若有興趣能夠看一下MVC5中過獲取過濾器代碼
public class FilterProviderCollection : Collection<IFilterProvider> { private static FilterComparer _filterComparer = new FilterComparer(); private IFilterProvider[] _combinedItems; private IDependencyResolver _dependencyResolver; //先執行父類Collection<IFilterProvider>的無參數構造函數,建立一個私有變量來保存 【過濾器的提供器】 public FilterProviderCollection() { } public FilterProviderCollection(IList<IFilterProvider> providers) : base(providers) { } internal FilterProviderCollection(IList<IFilterProvider> list, IDependencyResolver dependencyResolver) : base(list) { _dependencyResolver = dependencyResolver; } //其實獲得的是添加到該集合中的全部【過濾器】的【提供器】。 internal IFilterProvider[] CombinedItems { get { IFilterProvider[] combinedItems = _combinedItems; if (combinedItems == null) { //Items是父類Collection<IFilterProvider>中的一個屬性,獲得添加到該集合中的全部【過濾器】的【提供器】。 //經過GetCombined方法將 【一個空的IEnumerable<IFilterProvider>集合】 和 【原來的過濾器的提供器集合】鏈接,並轉換爲IFilterProvider數組類型,返回。 //這裏的【一個空的IEnumerable<IFilterProvider>集合】是經過DefaultDependencyResolver的GetServices方法獲取的。(原來定義這個的功能是反射建立實例,這裏返回空的集合,多是爲下一個版本作擴展而留下的吧) combinedItems = MultiServiceResolver.GetCombined<IFilterProvider>(Items, _dependencyResolver); _combinedItems = combinedItems; } return combinedItems; } } private static bool AllowMultiple(object filterInstance) { IMvcFilter mvcFilter = filterInstance as IMvcFilter; if (mvcFilter == null) { return true; } return mvcFilter.AllowMultiple; } //獲取篩選器 public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (actionDescriptor == null) { throw new ArgumentNullException("actionDescriptor"); } //獲得全部的過濾器提供器。(實例化FilterProviders時候添加的那 3 個 【GlobalFilters.Filters(也就是new GlobalFilterCollection())】、【new FilterAttributeFilterProvider()】、【new ControllerInstanceFilterProvider()】) IFilterProvider[] providers = CombinedItems; List<Filter> filters = new List<Filter>(); for (int i = 0; i < providers.Length; i++) { //第一個是GlobalFilterCollection對象,其繼承自IFilterProvider。(在Global.ascx文件的RegisterGlobalFilters方法中,添加過濾器到此過濾器提供器中) //第二個是FilterAttributeFilterProvider對象,也繼承自IFilterProvider。 IFilterProvider provider = providers[i]; //第一個GlobalFilterCollection,GetFilters方法獲得就是當前GlobalFilterCollection對象(它實現了IEnumerable,因此也是集合)。而foreach遍歷的是該對象的變量_filters中的值,並將值添加到此方法中聲明的局部變量filters中。到===第一個中設計兩個知識點:迭代,接口點方法 //第二個FilterAttributeFilterProvider,GetFilters方法得的是Controller上應用的過濾器和Action上應用的過濾器 foreach (Filter filter in provider.GetFilters(controllerContext, actionDescriptor)) { filters.Add(filter); } } filters.Sort(_filterComparer); if (filters.Count > 1) { RemoveDuplicates(filters); } return filters; } private static void RemoveDuplicates(List<Filter> filters) { HashSet<Type> visitedTypes = new HashSet<Type>(); // Remove duplicates from the back forward for (int i = filters.Count - 1; i >= 0; i--) { Filter filter = filters[i]; object filterInstance = filter.Instance; Type filterInstanceType = filterInstance.GetType(); if (!visitedTypes.Contains(filterInstanceType) || AllowMultiple(filterInstance)) { visitedTypes.Add(filterInstanceType); } else { filters.RemoveAt(i); } } } protected override void ClearItems() { _combinedItems = null; base.ClearItems(); } protected override void InsertItem(int index, IFilterProvider item) { _combinedItems = null; base.InsertItem(index, item); } protected override void RemoveItem(int index) { _combinedItems = null; base.RemoveItem(index); } protected override void SetItem(int index, IFilterProvider item) { _combinedItems = null; base.SetItem(index, item); } private class FilterComparer : IComparer<Filter> { public int Compare(Filter x, Filter y) { // Nulls always have to be less than non-nulls if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } // Sort first by order... if (x.Order < y.Order) { return -1; } if (x.Order > y.Order) { return 1; } // ...then by scope if (x.Scope < y.Scope) { return -1; } if (x.Scope > y.Scope) { return 1; } return 0; } } }
internal static class MultiServiceResolver { //過濾器時TService=IFilterProvider internal static TService[] GetCombined<TService>(IList<TService> items, IDependencyResolver resolver = null) where TService : class { if (resolver == null) { resolver = DependencyResolver.Current; } //resolver.GetServices<TService>()方法內部執行 return Enumerable.Empty<object>(); ,也就返回了一個空的Objcect類型集合IEnumerable<object> 。 IEnumerable<TService> services = resolver.GetServices<TService>(); //Concat方法鏈接兩個序列,應該是將 【空的IEnumerable<TService>集合】和【原來添加的過濾器提供器的集合】鏈接起來,並轉換爲數組類型。(其實仍是【過濾器提供器的集合】) return services.Concat(items).ToArray(); } }
三、AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
執行Authorize受權過濾器,其實就是執過濾器的OnAuthorization方法。AuthorizeAttribute是一個MVC的受權過濾器,可參考定義本身的受權過濾器。受權過濾器本質上是去讀取cookie,檢查cookie中相應的值是否和受權過濾器中設置的一致(能夠用來作登陸以後才能訪問某頁面的功能)。
public class ControllerActionInvoker : IActionInvoker { public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try { //執行Authorize過濾器 AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor); if (authContext.Result != null) { //沒有經過過濾器,按照自定義的ActionResult直接進行View的呈現 //View的呈現 InvokeActionResult(controllerContext, authContext.Result); } //省略其餘代碼 } return true; } return false; } protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor) { AuthorizationContext context = new AuthorizationContext(controllerContext, actionDescriptor); foreach (IAuthorizationFilter filter in filters) { //當沒有經過Authorize過濾器時,OnAuthorization方法中會建立一個ActionResult對象並賦值給Result屬性 filter.OnAuthorization(context); if (context.Result != null) { //若是有任意Authorize過濾器未經過,則跳出循環再也不繼續執行其餘Authorize過濾器 break; } } return context; } }
上述代碼中,遍歷全部的Authorize受權過濾器並執行其OnAuthorization方法,在OnAuthorization方法中,若是請求不知足條件,則建立一個ActionResult對象並賦值給AuthorizationContext對象的Result屬性,以後直接使用該ActionResult進行View的呈現。
在MVC中,AuthorizeAttribute是微軟定義的一個受權過濾器,它的OnAuthorization方法中規定,若是不知足條件的話,就跳轉到登陸頁面(在WebConfig文件中配置)。
四、IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
模型綁定,獲取Action方法參數對象的實參。詳細請看:白話學習MVC(六)模型綁定
五、ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
執行【方法過濾器】(實現IActionFilter接口)並執行Action方法內的代碼
public class ControllerActionInvoker : IActionInvoker { public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try { AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor); if (authContext.Result != null) { InvokeActionResult(controllerContext, authContext.Result); } else { if (controllerContext.Controller.ValidateRequest) { ValidateRequest(controllerContext); } IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor); //執行【方法過濾器】(實現IActionFilter接口)並執行Action方法內的代碼 ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result); } } catch (ThreadAbortException) { // This type of exception occurs as a result of Response.Redirect(), but we special-case so that // the filters don't see this as an error. throw; } catch (Exception ex) { // something blew up, so execute the exception filters ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex); if (!exceptionContext.ExceptionHandled) { throw; } InvokeActionResult(controllerContext, exceptionContext.Result); } return true; } // notify controller that no method matched return false; } protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) { ////建立Executing上下文,其中封裝了請求上下文、當前Controller,當前Action,當前Action的參數 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters); //將【Action內代碼的執行】添加到委託中 Func<ActionExecutedContext> continuation = () => new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) { //InvokeActionMethod執行Action方法內的代碼,並返回方法的返回值。 Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters) }; //------------------調炸天的一句代碼------------------ //代碼的實現是在InvokeActionMethodFilter方法中, //此句代碼保證了在InvokeActionMethodFilter方法中,先循環執行全部的【方法過濾器】的ActionExecting方法,而後再執行Action方法內的代碼,最後再循環執行全部的【方法過濾器】的ActionExected方法 Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation, (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next)); return thunk(); } //執行Action內的代碼,並獲取返回值! protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) { //執行Action方法內的代碼。 //actionDescriptor是一個ReflectedActionDescriptor對象 object returnValue = actionDescriptor.Execute(controllerContext, parameters); ActionResult result = CreateActionResult(controllerContext, actionDescriptor, returnValue); return result; } internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation) { //代碼的實現是在InvokeActionMethodFilter方法中 //首先,循環執行應用在Action上的全部過濾器的ActionExecuting,若是沒有經過,則按照定義在ActionExecuting方法中建立的ActionResult(Result=New ActionResult())去執行view的呈現,不在繼續執行! //若是經過(則Result==null,默認),那麼執行Action方法內的代碼,並將Action方法的返回值設置給上下文對象的Result屬性! //若是Action內的方法的執行出現異常,那麼再也不去執行過濾器的ActionExecuted。不然,繼續執行過濾器的ActionExecuted //執行ActionExecuted,參數爲Action上下文(Result=Action方法內的返回值)。 //若是沒有經過ActionExecuted,那麼就更改上下文中的Result爲本身定義的ActionReuslt,並設置到上下文中。 //返回這個上下文,view的呈現時,便使用這個ActionResult做爲返回值。 //執行Action過濾器的ActionExecuting方法 filter.OnActionExecuting(preContext); //過濾器是否經過的判斷爲:是否在方法中定義了返回結果 if (preContext.Result != null) { //沒有經過 return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */) { Result = preContext.Result }; } //經過了ActionExecuting bool wasError = false; ActionExecutedContext postContext = null; //以上代碼循環全部的filter,所有執行一次!以後再繼續執行... //執行Action方法內的代碼 try { //執行InvokeActionMethodWithFilters方法中的continuation委託。==也就是執行Action方法內的代碼 postContext = continuation(); } catch (ThreadAbortException) { // This type of exception occurs as a result of Response.Redirect(), but we special-case so that // the filters don't see this as an error. postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, null /* exception */); filter.OnActionExecuted(postContext); throw; } catch (Exception ex) { wasError = true; postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, ex); filter.OnActionExecuted(postContext); if (!postContext.ExceptionHandled) { throw; } } //循環執行全部的ActionExecuted //在循環全部的filter執行循環的時候return以前的! if (!wasError) { filter.OnActionExecuted(postContext); } //最終返回 return postContext; } }
上述代碼,首先循環執行全部Action過濾器的ActionExecuting方法,而後執行Action方法內的代碼,最後再循環執行全部的Action過濾器的ActionExecuted方法。此過程的過濾器中,若是不知足過濾器的要求,則直接利用自定義的ActionResult對象進行View的呈現!
在執行Action方法內部代碼時,那些返回值:return Content()、return View()、return Json()等,其實都是執行Controller類的方法,這些方法內建立繼承自ActionResult類的ContentResult、ViewResult、JsonResult的對象並返回。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //僅列舉部分方法 protected internal FileContentResult File(byte[] fileContents, string contentType) { return File(fileContents, contentType, null /* fileDownloadName */); } protected internal virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName) { return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName }; } protected internal FileStreamResult File(Stream fileStream, string contentType) { return File(fileStream, contentType, null /* fileDownloadName */); } protected internal virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName) { return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName }; } protected internal FilePathResult File(string fileName, string contentType) { return File(fileName, contentType, null /* fileDownloadName */); } protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName) { return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName }; } protected virtual void HandleUnknownAction(string actionName) { throw new HttpException(404, String.Format(CultureInfo.CurrentCulture, MvcResources.Controller_UnknownAction, actionName, GetType().FullName)); } protected internal HttpNotFoundResult HttpNotFound() { return HttpNotFound(null); } protected internal virtual HttpNotFoundResult HttpNotFound(string statusDescription) { return new HttpNotFoundResult(statusDescription); } protected internal virtual JavaScriptResult JavaScript(string script) { return new JavaScriptResult { Script = script }; } protected internal JsonResult Json(object data) { return Json(data, null /* contentType */, null /* contentEncoding */, JsonRequestBehavior.DenyGet); } protected internal JsonResult Json(object data, string contentType) { return Json(data, contentType, null /* contentEncoding */, JsonRequestBehavior.DenyGet); } protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding) { return Json(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet); } protected internal JsonResult Json(object data, JsonRequestBehavior behavior) { return Json(data, null /* contentType */, null /* contentEncoding */, behavior); } protected internal JsonResult Json(object data, string contentType, JsonRequestBehavior behavior) { return Json(data, contentType, null /* contentEncoding */, behavior); } protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) { return new JsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior }; } }
補充:過濾器的ActionExecuting方法和ActionExecuted方法的執行是按照一條龍的順序執行的。
此圖摘自:http://www.cnblogs.com/artech/archive/2012/08/06/action-filter.html
重要:InvokeActionMethodWithFilters方法中的那句碉堡的代碼實現了一條龍的方式去【OnActionExecuting】和【OnActionExecuted】方法,必需要好好學習下!!!
六、InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);
執行【結果過濾器】(實現IResultFilter接口),再作View的呈現。
public class ControllerActionInvoker : IActionInvoker { public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try { AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor); if (authContext.Result != null) { InvokeActionResult(controllerContext, authContext.Result); } else { if (controllerContext.Controller.ValidateRequest) { ValidateRequest(controllerContext); } IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor); ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); //執行【結果過濾器】(實現IResultFilter接口),再作View的呈現。(執行的模式和上一句代碼的執行模式相同!) InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result); } } catch (ThreadAbortException) { // This type of exception occurs as a result of Response.Redirect(), but we special-case so that // the filters don't see this as an error. throw; } catch (Exception ex) { // something blew up, so execute the exception filters ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex); if (!exceptionContext.ExceptionHandled) { throw; } InvokeActionResult(controllerContext, exceptionContext.Result); } return true; } // notify controller that no method matched return false; } protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult) { ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult); //將View的呈現加入到委託鏈中 Func<ResultExecutedContext> continuation = delegate { //執行View的呈現 InvokeActionResult(controllerContext, actionResult); return new ResultExecutedContext(controllerContext, actionResult, false /* canceled */, null /* exception */); }; //先循環執行全部的Result過濾器的OnResultExecuting方法,而後執行View的呈現,再循環執行全部的Result過濾器的OnResultExecuted方法 //執行過濾器方法時候仍是一條龍的方式 Func<ResultExecutedContext> thunk = filters.Reverse().Aggregate(continuation, (next, filter) => () => InvokeActionResultFilter(filter, preContext, next)); return thunk(); } internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func<ResultExecutedContext> continuation) { //循環執行全部的Result過濾器的OnResultExecuting方法 filter.OnResultExecuting(preContext); if (preContext.Cancel) { return new ResultExecutedContext(preContext, preContext.Result, true /* canceled */, null /* exception */); } bool wasError = false; ResultExecutedContext postContext = null; try { //執行委託,委託鏈中的InvokeActionResult方法進行View的呈現! postContext = continuation(); } catch (ThreadAbortException) { // This type of exception occurs as a result of Response.Redirect(), but we special-case so that // the filters don't see this as an error. postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, null /* exception */); filter.OnResultExecuted(postContext); throw; } catch (Exception ex) { wasError = true; postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, ex); filter.OnResultExecuted(postContext); if (!postContext.ExceptionHandled) { throw; } } if (!wasError) { //循環執行全部的Result過濾器的OnResultExecuted方法 //擴展:因爲過濾器的此方法是在View的呈現以後,因此能夠利用Result過濾器的OnResultExecuted在今生成靜態頁 filter.OnResultExecuted(postContext); } return postContext; } }
上述代碼中,先循環執行全部的Result過濾器的OnResultExecuting方法,而後執行View的呈現,再循環執行全部的Result過濾器的OnResultExecuted方法。執行流程也是一條龍的方方式!
以上全部就是Action執行的所有,若是不符之處,請指正!由以上的執行可知【View的呈現】是經過ControllerActionInvoker類的InvokeActionResult方法來實現的,下一篇就來詳細分析View的呈現相關的知識!