白話學習MVC(八)Action的執行二

1、概述

  上篇博文《白話學習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();
            }
        }
    }    

 

2、詳細分析

  概述中的紅色字體部分,也就是咱們上一節中遺留的代碼段,它實現了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()));
        }
Global.asax
    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;
        }
    }
MyControllerActivator.cs
public class MyActionInvoker : AsyncControllerActionInvoker
    {
        public override bool InvokeAction(System.Web.Mvc.ControllerContext controllerContext, string actionName)
        {
            //本身來實現Action的執行
        }
    }
MyActionInvoker.cs

   上面指出兩部份內容,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方法
    }    
AsyncControllerActionInvoker
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;
        }
}
MVC5:ControllerActionInvoker

 

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;
    }
}
ControllerActionInvoker
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);
    }
}
ReflectedControllerDescriptor
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
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);
            }
        }
    }
}
MVC5:ActionMethodSelector

 

 二、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);
            //省略其餘代碼
        }

    }
}
ControllerActionInvoker
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; }
}
FilterProviders
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;
        }
    }
}
FilterProviderCollection
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()); }
    }
}
MultiServiceResolver
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);
        }
    }
}
GlobalFilterCollection
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);
            }
        }             
    }
}
FilterAttributeFilterProvider
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);
        }
    }
}
ControllerInstanceFilterProvider
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; }
    }
}
FilterInfo

  上述代碼中,實現了獲取過濾器,而過濾器能夠經過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;
        }
    }
}
MVC5:FilterProviderCollection
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();
    } 
}
MVC5:MultiServiceResolver

 

 三、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;
    }
}
ControllerActionInvoker

 

  上述代碼中,遍歷全部的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;
    }
}
ControllerActionInvoker

  上述代碼,首先循環執行全部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
        };
    }
}
Controller

 

補充:過濾器的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;
    }

}
ControllerActionInvoker

   上述代碼中,先循環執行全部的Result過濾器的OnResultExecuting方法,而後執行View的呈現,再循環執行全部的Result過濾器的OnResultExecuted方法。執行流程也是一條龍的方方式!

   以上全部就是Action執行的所有,若是不符之處,請指正!由以上的執行可知【View的呈現】是經過ControllerActionInvoker類的InvokeActionResult方法來實現的,下一篇就來詳細分析View的呈現相關的知識!

相關文章
相關標籤/搜索