• MVC控制器执行


    通过前篇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)
    

    本文参考文档:

  • 相关阅读:
    路由懒加载的实现
    vue中的tab栏切换内容变换
    H5页面的高度宽度100%
    vue中的路由的跳转的参数
    xxxx-xx-xx的时间的加减
    sql server 2008 R2 备份还原到sql 2012
    eval方法将字符串转换成json对象
    CSS3 圆角(border-radius)
    [Easyui
    JavaScript slice() 方法
  • 原文地址:https://www.cnblogs.com/Dewumu/p/13935880.html
Copyright © 2020-2023  润新知