上篇博文《白话学习MVC(七)Action的执行一》介绍了ASP.NET MVC中Action的执行的简要流程,并且对TempData的运行机制进行了详细的分析,本篇来分析上一篇中遗留的【3-2、ActionInvoker.InvokeAction(ControllerContext, actionName)】部分的内容,其中包含了Action的执行、过滤器的执行、View的呈现(下节介绍)。
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的执行!
1、创建自定义一个ActionInvoker(实现IActionInvoker接口的类或者直接继承AsyncControllerActonInvoker类)。
2、创建好自定义的ActionInvoker之后,就需要将我们的ActionInvoker设置到系统中,就是通过请求的控制器HomeController的基类Controller的这个ActionInvoker属性来进行设置。所以,我们就需要在HomeController被激活时,直接执行该控制器实例的ActionInvoker属性来设置,而控制器的激活是在一个ControllerActivator的Create方法中完成的,ControllerActivator的选择又是ControllerFactory来做的!
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
上面指出两部分内容,一、在默认情况下的ActionInvoker(AsyncControllerActonInvoker);二、使用自定义ActionInvoker。我们所提到的ActionInvoker都是泛指实现了IActionInvoker接口的类,而上述两个中情况【默认ActionInvoker(AsyncControllerActonInvoker)】和【自定义ActionInvoker】便是实现了IActionInvoker接口,并实现了该接口中唯一的一个方法InvokeAction,而实现的这个方法中包含了对Action执行的所有操作,下面就来看看默认情况下ActionInvoker(AsyncControllerActonInvoker)的InvokeAction方法中是如何定义的!其实,自定义ActionInvoker的InvokeAction方法也是仿照AsyncControllerActonInvoker类来实现的。
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的呈现(下一节介绍)。
扩展:此处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方法解析
1、ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);
在控制器HomeController对象的所有方法中,找到当前请求的Action(控制器对象的一个方法)。
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特性的方法,并筛选得到特性的名字=actionName的特性 //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); } } } }MVC5:ActionMethodSelector
2、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种方式添加:1、Global.asax中的RegisterGlobalFilters方法,Scope=10;2、在控制器HomeController上以特性的方法添加,Scope=20;3、在Action上以特性的方式添加,Scope=30;4、控制器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
3、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文件中配置)。
4、IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
模型绑定,获取Action方法参数对象的实参。详细请看:白话学习MVC(六)模型绑定
5、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】方法,必须要好好学习下!!!
6、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的呈现相关的知识!