通过前篇MVC处理程序&Asp.Net路由机制我们了解了MVC路由解析及控制器创建。
得到控制器之后就是执行了
// System.Web.Mvc.IController
/// <summary>Executes the specified request context.</summary>
/// <param name="requestContext">The request context.</param>
void Execute(RequestContext requestContext);
IController的接口,就一个方法Execute的方法,参数为RequestConext
graph LR
IController-->ControllerBase
ControllerBase-->Controller
以上是Controller的继承关系
IContrller接口的Execute被ControllerBase实现
// System.Web.Mvc.ControllerBase
/// <summary>Executes the specified request context.</summary>
/// <param name="requestContext">The request context.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext" /> parameter is null.</exception>
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (requestContext.HttpContext == null)
{
throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext");
}
this.VerifyExecuteCalledOnce();
this.Initialize(requestContext);
using (ScopeStorage.CreateTransientScope())
{
this.ExecuteCore();
}
}
// System.Web.Mvc.ControllerBase
/// <summary>Initializes the specified request context.</summary>
/// <param name="requestContext">The request context.</param>
protected virtual void Initialize(RequestContext requestContext)
{
this.ControllerContext = new ControllerContext(requestContext, this);
}
// System.Web.Mvc.Controller
/// <summary>Initializes data that might not be available when the constructor is called.</summary>
/// <param name="requestContext">The HTTP context and route data.</param>
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Url = new UrlHelper(requestContext);
}
Execute方法,VerifyExecuteCalledOnce()看方法名的意思应该是验证是否是第一次执行,Initialize()就是将请求的上下文和Controller做个了绑定,ScopeStorage.CreateTransientScope()然后using了一个作用域,最后交给子类的ExecuteCore方法
// System.Web.Mvc.Controller
/// <summary>Invokes the action in the current controller context.</summary>
protected override void ExecuteCore()
{
this.PossiblyLoadTempData();
try
{
string actionName = Controller.GetActionName(this.RouteData);
if (!this.ActionInvoker.InvokeAction(base.ControllerContext, actionName))
{
this.HandleUnknownAction(actionName);
}
}
finally
{
this.PossiblySaveTempData();
}
}
PossiblyLoadTempData()看方法名就知道是加载TempData,PossiblySaveTempData()是保存TempData
// System.Web.Mvc.Controller
internal void PossiblyLoadTempData()
{
if (!base.ControllerContext.IsChildAction)
{
base.TempData.Load(base.ControllerContext, this.TempDataProvider);
}
}
// System.Web.Mvc.TempDataDictionary
/// <summary>Loads the specified controller context by using the specified data provider.</summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="tempDataProvider">The temporary data provider.</param>
public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider)
{
IDictionary<string, object> dictionary = tempDataProvider.LoadTempData(controllerContext);
this._data = ((dictionary != null) ? new Dictionary<string, object>(dictionary, StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
this._initialKeys = new HashSet<string>(this._data.Keys, StringComparer.OrdinalIgnoreCase);
this._retainedKeys.Clear();
}
// System.Web.Mvc.SessionStateTempDataProvider
/// <summary>Loads the temporary data by using the specified controller context.</summary>
/// <returns>The temporary data.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <exception cref="T:System.InvalidOperationException">An error occurred when the session context was being retrieved.</exception>
public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
HttpSessionStateBase session = controllerContext.HttpContext.Session;
if (session != null)
{
Dictionary<string, object> dictionary = session["__ControllerTempData"] as Dictionary<string, object>;
if (dictionary != null)
{
session.Remove("__ControllerTempData");
return dictionary;
}
}
return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
}
// System.Web.Mvc.Controller
internal void PossiblySaveTempData()
{
if (!base.ControllerContext.IsChildAction)
{
base.TempData.Save(base.ControllerContext, this.TempDataProvider);
}
}
// System.Web.Mvc.TempDataDictionary
/// <summary>Saves the specified controller context by using the specified data provider.</summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="tempDataProvider">The temporary data provider.</param>
public void Save(ControllerContext controllerContext, ITempDataProvider tempDataProvider)
{
this._data.RemoveFromDictionary(delegate(KeyValuePair<string, object> entry, TempDataDictionary tempData)
{
string key = entry.Key;
return !tempData._initialKeys.Contains(key) && !tempData._retainedKeys.Contains(key);
}
, this);
tempDataProvider.SaveTempData(controllerContext, this._data);
}
// System.Web.Mvc.SessionStateTempDataProvider
/// <summary>Saves the specified values in the temporary data dictionary by using the specified controller context.</summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="values">The values.</param>
/// <exception cref="T:System.InvalidOperationException">An error occurred the session context was being retrieved.</exception>
public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
HttpSessionStateBase session = controllerContext.HttpContext.Session;
bool flag = values != null && values.Count > 0;
if (session == null)
{
if (flag)
{
throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
}
}
else
{
if (flag)
{
session["__ControllerTempData"] = values;
return;
}
if (session["__ControllerTempData"] != null)
{
session.Remove("__ControllerTempData");
}
}
}
回到Controller ExecuteCore()方法中
string actionName = Controller.GetActionName(this.RouteData);
通过路由获取actionName,调用ActionInvoker.InvokeAction如果返回false,就抛出异常
// System.Web.Mvc.Controller
/// <summary>Gets the action invoker for the controller.</summary>
/// <returns>The action invoker.</returns>
public IActionInvoker ActionInvoker
{
get
{
if (this._actionInvoker == null)
{
this._actionInvoker = this.CreateActionInvoker();
}
return this._actionInvoker;
}
set
{
this._actionInvoker = value;
}
}
// System.Web.Mvc.Controller
/// <summary>Creates an action invoker.</summary>
/// <returns>An action invoker.</returns>
protected virtual IActionInvoker CreateActionInvoker()
{
IAsyncActionInvokerFactory service = this.Resolver.GetService<IAsyncActionInvokerFactory>();
if (service != null)
{
return service.CreateInstance();
}
IActionInvokerFactory service2 = this.Resolver.GetService<IActionInvokerFactory>();
if (service2 != null)
{
return service2.CreateInstance();
}
IAsyncActionInvoker arg_4F_0;
if ((arg_4F_0 = this.Resolver.GetService<IAsyncActionInvoker>()) == null)
{
arg_4F_0 = (this.Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker());
}
return arg_4F_0;
}
ActionInvoker默认取异步IAsyncActionInvoker,没有则取IActionInvoker,最终InvokeAction是在ControllerActionInvoker里面实现的
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Invokes the specified action by using the specified controller context.</summary>
/// <returns>The result of executing the action.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionName">The name of the action to invoke.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext" /> parameter is null.</exception>
/// <exception cref="T:System.ArgumentException">The <paramref name="actionName" /> parameter is null or empty.</exception>
/// <exception cref="T:System.Threading.ThreadAbortException">The thread was aborted during invocation of the action.</exception>
/// <exception cref="T:System.Exception">An unspecified error occurred during invocation of the action.</exception>
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor != null)
{
FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
try
{
AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);
if (authenticationContext.Result != null)
{
AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);
}
else
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
if (authorizationContext.Result != null)
{
AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ControllerActionInvoker.ValidateRequest(controllerContext);
}
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result);
}
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
if (!exceptionContext.ExceptionHandled)
{
throw;
}
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
return false;
}
ControllerActionInvoker.InvokeAction()先获得了两个Descriptor
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Retrieves information about the controller by using the specified controller context.</summary>
/// <returns>Information about the controller.</returns>
/// <param name="controllerContext">The controller context.</param>
protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
{
Type type = controllerContext.Controller.GetType();
return this.DescriptorCache.GetDescriptor<Type>(type, (Type innerType) => new ReflectedControllerDescriptor(innerType), type);
}
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Finds the information about the action method.</summary>
/// <returns>Information about the action method.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="controllerDescriptor">The controller descriptor.</param>
/// <param name="actionName">The name of the action.</param>
protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
if (!controllerContext.RouteData.HasDirectRouteMatch())
{
return controllerDescriptor.FindAction(controllerContext, actionName);
}
List<DirectRouteCandidate> directRouteCandidates = ControllerActionInvoker.GetDirectRouteCandidates(controllerContext);
DirectRouteCandidate directRouteCandidate = DirectRouteCandidate.SelectBestCandidate(directRouteCandidates, controllerContext);
if (directRouteCandidate == null)
{
return null;
}
controllerContext.RouteData = directRouteCandidate.RouteData;
controllerContext.RequestContext.RouteData = directRouteCandidate.RouteData;
directRouteCandidate.RouteData.Values.RemoveFromDictionary((KeyValuePair<string, object> entry) => entry.Value == UrlParameter.Optional);
return directRouteCandidate.ActionDescriptor;
}
首先获得Controller的Type,然后从DescriptorCache(缓存)获取ControllerDescriptor。如果没有的话 就使用ReflectedControllerDescriptor
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Finds the information about the action method.</summary>
/// <returns>Information about the action method.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="controllerDescriptor">The controller descriptor.</param>
/// <param name="actionName">The name of the action.</param>
protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
if (!controllerContext.RouteData.HasDirectRouteMatch())
{
return controllerDescriptor.FindAction(controllerContext, actionName);
}
List<DirectRouteCandidate> directRouteCandidates = ControllerActionInvoker.GetDirectRouteCandidates(controllerContext);
DirectRouteCandidate directRouteCandidate = DirectRouteCandidate.SelectBestCandidate(directRouteCandidates, controllerContext);
if (directRouteCandidate == null)
{
return null;
}
controllerContext.RouteData = directRouteCandidate.RouteData;
controllerContext.RequestContext.RouteData = directRouteCandidate.RouteData;
directRouteCandidate.RouteData.Values.RemoveFromDictionary((KeyValuePair<string, object> entry) => entry.Value == UrlParameter.Optional);
return directRouteCandidate.ActionDescriptor;
}
// System.Web.Mvc.Routing.DirectRouteExtensions
public static bool HasDirectRouteMatch(this RouteData routeData)
{
if (routeData == null)
{
throw Error.ArgumentNull("routeData");
}
return routeData.Values.ContainsKey("MS_DirectRouteMatches");
}
// System.Web.Mvc.ReflectedControllerDescriptor
/// <summary>Finds the specified action for the specified controller context.</summary>
/// <returns>The information about the action.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionName">The name of the action.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext" /> parameter is null.</exception>
/// <exception cref="T:System.ArgumentException">The <paramref name="actionName" /> parameter is null or empty.</exception>
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");
}
MethodInfo methodInfo = this._selector.FindActionMethod(controllerContext, actionName);
if (methodInfo == null)
{
return null;
}
return new ReflectedActionDescriptor(methodInfo, actionName, this);
}
接下来是获取ActionDescriptor,先检查路由是否有MS_DirectRouteMatches,没有则返回控制器中的ActionDescriptor没有就提供一个ReflectedActionDescriptor,有则从路由中取
// System.Web.Mvc.ControllerActionInvoker
private static List<DirectRouteCandidate> GetDirectRouteCandidates(ControllerContext controllerContext)
{
List<DirectRouteCandidate> list = new List<DirectRouteCandidate>();
RouteData routeData = controllerContext.RouteData;
foreach (RouteData current in routeData.GetDirectRouteMatches())
{
if (current != null)
{
if (current.GetTargetControllerDescriptor() == null)
{
throw new InvalidOperationException(MvcResources.DirectRoute_MissingControllerDescriptor);
}
ActionDescriptor[] targetActionDescriptors = current.GetTargetActionDescriptors();
if (targetActionDescriptors == null || targetActionDescriptors.Length == 0)
{
throw new InvalidOperationException(MvcResources.DirectRoute_MissingActionDescriptors);
}
ActionDescriptor[] array = targetActionDescriptors;
for (int i = 0; i < array.Length; i++)
{
ActionDescriptor actionDescriptor = array[i];
if (actionDescriptor != null)
{
list.Add(new DirectRouteCandidate
{
ActionDescriptor = actionDescriptor,
ActionNameSelectors = actionDescriptor.GetNameSelectors(),
ActionSelectors = actionDescriptor.GetSelectors(),
Order = current.GetOrder(),
Precedence = current.GetPrecedence(),
RouteData = current
});
}
}
}
}
return list;
}
// System.Web.Mvc.Routing.DirectRouteExtensions
public static ActionDescriptor[] GetTargetActionDescriptors(this RouteData routeData)
{
return routeData.GetRouteDataTokenValue("MS_DirectRouteActions");
}
回到ControllerActionInvoker.InvokeAction()中,获取两个Descriptor之后,获取FilterInfo
FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Retrieves information about the action filters.</summary>
/// <returns>Information about the action filters.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionDescriptor">The action descriptor.</param>
protected virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return new FilterInfo(this._getFiltersThunk(controllerContext, actionDescriptor));
}
// System.Web.Mvc.ControllerActionInvoker
private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = new Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>>(FilterProviders.Providers.GetFilters);
using System;
namespace System.Web.Mvc
{
/// <summary>Provides a registration point for filters.</summary>
public static class FilterProviders
{
/// <summary>Provides a registration point for filters.</summary>
/// <returns>The collection of filters.</returns>
public static FilterProviderCollection Providers
{
get;
private set;
}
static FilterProviders()
{
FilterProviders.Providers = new FilterProviderCollection();
FilterProviders.Providers.Add(GlobalFilters.Filters);
FilterProviders.Providers.Add(new FilterAttributeFilterProvider());
FilterProviders.Providers.Add(new ControllerInstanceFilterProvider());
}
}
}
实例化FilterInfo需要注册Filter,在静态类FilterProviders中分别对Global、FilterAttribute、ControllerInstance的Filter注册,然后对Filter分类整理
/// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.FilterInfo" /> class using the specified filters collection.</summary>
/// <param name="filters">The filters collection.</param>
public FilterInfo(IEnumerable<Filter> filters)
{
FilterInfo.OverrideFilterInfo info = FilterInfo.ProcessOverrideFilters(filters);
this.SplitFilters(info);
}
// System.Web.Mvc.FilterInfo
private static FilterInfo.OverrideFilterInfo ProcessOverrideFilters(IEnumerable<Filter> filters)
{
FilterInfo.OverrideFilterInfo result = new FilterInfo.OverrideFilterInfo
{
ActionOverrideScope = FilterScope.First,
AuthenticationOverrideScope = FilterScope.First,
AuthorizationOverrideScope = FilterScope.First,
ExceptionOverrideScope = FilterScope.First,
ResultOverrideScope = FilterScope.First,
Filters = new List<Filter>()
};
foreach (Filter current in filters)
{
if (current != null)
{
IOverrideFilter overrideFilter = current.Instance as IOverrideFilter;
if (overrideFilter != null)
{
if (overrideFilter.FiltersToOverride == typeof(IActionFilter) && current.Scope >= result.ActionOverrideScope)
{
result.ActionOverrideScope = current.Scope;
}
else
{
if (overrideFilter.FiltersToOverride == typeof(IAuthenticationFilter) && current.Scope >= result.AuthenticationOverrideScope)
{
result.AuthenticationOverrideScope = current.Scope;
}
else
{
if (overrideFilter.FiltersToOverride == typeof(IAuthorizationFilter) && current.Scope >= result.AuthorizationOverrideScope)
{
result.AuthorizationOverrideScope = current.Scope;
}
else
{
if (overrideFilter.FiltersToOverride == typeof(IExceptionFilter) && current.Scope >= result.ExceptionOverrideScope)
{
result.ExceptionOverrideScope = current.Scope;
}
else
{
if (overrideFilter.FiltersToOverride == typeof(IResultFilter) && current.Scope >= result.ResultOverrideScope)
{
result.ResultOverrideScope = current.Scope;
}
}
}
}
}
}
result.Filters.Add(current);
}
}
return result;
}
// System.Web.Mvc.FilterInfo
private void SplitFilters(FilterInfo.OverrideFilterInfo info)
{
foreach (Filter current in info.Filters)
{
IActionFilter actionFilter = current.Instance as IActionFilter;
if (actionFilter != null && current.Scope >= info.ActionOverrideScope)
{
this._actionFilters.Add(actionFilter);
}
IAuthenticationFilter authenticationFilter = current.Instance as IAuthenticationFilter;
if (authenticationFilter != null && current.Scope >= info.AuthenticationOverrideScope)
{
this._authenticationFilters.Add(authenticationFilter);
}
IAuthorizationFilter authorizationFilter = current.Instance as IAuthorizationFilter;
if (authorizationFilter != null && current.Scope >= info.AuthorizationOverrideScope)
{
this._authorizationFilters.Add(authorizationFilter);
}
IExceptionFilter exceptionFilter = current.Instance as IExceptionFilter;
if (exceptionFilter != null && current.Scope >= info.ExceptionOverrideScope)
{
this._exceptionFilters.Add(exceptionFilter);
}
IResultFilter resultFilter = current.Instance as IResultFilter;
if (resultFilter != null && current.Scope >= info.ResultOverrideScope)
{
this._resultFilters.Add(resultFilter);
}
}
}
回到ControllerActionInvoker.InvokeAction()继续执行InvokeAuthenticationFilters
// System.Web.Mvc.ControllerActionInvoker
protected virtual AuthenticationContext InvokeAuthenticationFilters(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
IPrincipal user = controllerContext.HttpContext.User;
AuthenticationContext authenticationContext = new AuthenticationContext(controllerContext, actionDescriptor, user);
foreach (IAuthenticationFilter current in filters)
{
current.OnAuthentication(authenticationContext);
if (authenticationContext.Result != null)
{
break;
}
}
IPrincipal principal = authenticationContext.Principal;
if (principal != user)
{
authenticationContext.HttpContext.User = principal;
Thread.CurrentPrincipal = principal;
}
return authenticationContext;
}
// System.Web.Mvc.Filters.IAuthenticationFilter
/// <summary>Authenticates the request.</summary>
/// <param name="filterContext">The context to use for authentication.</param>
void OnAuthentication(AuthenticationContext filterContext);
执行所有注册的IAuthenticationFilter.OnAuthentication()方法,如果返回有Result则跳出循环,执行ControllerActionInvoker.InvokeAuthenticationFiltersChallenge()并执行所有注册的IAuthenticationFilter.OnAuthenticationChallenge()方法,最后执行ControllerActionInvoker.InvokeActionResult()
// System.Web.Mvc.ControllerActionInvoker
protected virtual AuthenticationChallengeContext InvokeAuthenticationFiltersChallenge(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor, ActionResult result)
{
AuthenticationChallengeContext authenticationChallengeContext = new AuthenticationChallengeContext(controllerContext, actionDescriptor, result);
foreach (IAuthenticationFilter current in filters)
{
current.OnAuthenticationChallenge(authenticationChallengeContext);
}
return authenticationChallengeContext;
}
// System.Web.Mvc.Filters.IAuthenticationFilter
/// <summary>Adds an authentication challenge to the current <see cref="T:System.Web.Mvc.ActionResult" />.</summary>
/// <param name="filterContext">The context to use for the authentication challenge.</param>
void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Invokes the specified action result by using the specified controller context.</summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionResult">The action result.</param>
protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
{
actionResult.ExecuteResult(controllerContext);
}
没有返回Result,继续执行ControllerActionInvoker.InvokeAuthorizationFilters
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Invokes the specified authorization filters by using the specified action descriptor and controller context.</summary>
/// <returns>The context for the <see cref="T:System.Web.Mvc.AuthorizeAttribute" /> object.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="filters">The authorization filters.</param>
/// <param name="actionDescriptor">The action descriptor.</param>
protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter current in filters)
{
current.OnAuthorization(authorizationContext);
if (authorizationContext.Result != null)
{
break;
}
}
return authorizationContext;
}
// System.Web.Mvc.IAuthorizationFilter
/// <summary>Called when authorization is required.</summary>
/// <param name="filterContext">The filter context.</param>
void OnAuthorization(AuthorizationContext filterContext);
和前面同理,一个是身份验证,一个是检测是否授权
下一步ValidateRequest,验证请求
if (controllerContext.Controller.ValidateRequest)
{
ControllerActionInvoker.ValidateRequest(controllerContext);
}
// System.Web.Mvc.ControllerActionInvoker
internal static void ValidateRequest(ControllerContext controllerContext)
{
if (controllerContext.IsChildAction)
{
return;
}
HttpContext current = HttpContext.Current;
if (current != null)
{
ValidationUtility.EnableDynamicValidation(current);
}
controllerContext.HttpContext.Request.ValidateInput();
}
ControllerBase默认设置需要验证请求
// System.Web.Mvc.ControllerBase
/// <summary>Gets or sets a value that indicates whether request validation is enabled for this request.</summary>
/// <returns>true if request validation is enabled for this request; otherwise, false. The default is true.</returns>
public bool ValidateRequest
{
get
{
return this._validateRequest;
}
set
{
this._validateRequest = value;
}
}
private bool _validateRequest = true;
下一步 绑定Action参数
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
下一步 带ActionFilters并执行方法
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Invokes the specified action method by using the specified parameters, controller context, and action filters.</summary>
/// <returns>The context for the ActionExecuted method of the <see cref="T:System.Web.Mvc.ActionFilterAttribute" /> class.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="filters">The action filters.</param>
/// <param name="actionDescriptor">The action descriptor.</param>
/// <param name="parameters">The parameters.</param>
protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
{
Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
Func<ActionExecutedContext> func = filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next));
return func();
}
// System.Web.Mvc.ControllerActionInvoker
/// <summary>Invokes the specified action method by using the specified parameters and the controller context.</summary>
/// <returns>The result of executing the action method.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionDescriptor">The action descriptor.</param>
/// <param name="parameters">The parameters.</param>
protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
}
// System.Linq.Enumerable
[__DynamicallyInvokable]
public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (func == null)
{
throw Error.ArgumentNull("func");
}
TAccumulate tAccumulate = seed;
foreach (TSource current in source)
{
tAccumulate = func(tAccumulate, current);
}
return tAccumulate;
}
// System.Web.Mvc.ControllerActionInvoker
internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
{
filter.OnActionExecuting(preContext);
if (preContext.Result != null)
{
return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)
{
Result = preContext.Result
};
}
bool flag = false;
ActionExecutedContext actionExecutedContext = null;
try
{
actionExecutedContext = continuation();
}
catch (ThreadAbortException)
{
actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);
filter.OnActionExecuted(actionExecutedContext);
throw;
}
catch (Exception exception)
{
flag = true;
actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);
filter.OnActionExecuted(actionExecutedContext);
if (!actionExecutedContext.ExceptionHandled)
{
throw;
}
}
if (!flag)
{
filter.OnActionExecuted(actionExecutedContext);
}
return actionExecutedContext;
}
这里Filter执行流程类似于俄罗斯套娃
graph TD
A(ActionFilter_1.OnActionExecuting)-->B(ActionFilter_2.OnActionExecuting)
B-->|... ...|C(ActionFilter_n.OnActionExecuting)
C-->D(InvokeActionMethod)
D-->E(ActionFilter_n.OnActionExecuted)
E-->|... ...|F(ActionFilter_2.OnActionExecuted)
F-->G(ActionFilter_1.OnActionExecuted)
本文参考文档: