ASPNET MVC中断请求

ASPNET MVC如何正确的中断请求?

感觉是这样?

  在aspnet开发过程中如果想要中断当前的http处理,以前在aspnet中一直是Response.End();

  在这Response.End()之后的当前请求应有的代码都不会执行了,

  但是在aspnetmvc中,就算调用Response.End();还是会执行!!

          //aspnet webform
            if(ok)
                Response.End();
            //save不会继续执行
            Save();

            //aspnet mvc
            if (ok)
                Response.End();

            //save会继续执行
            Save();    

 

 aspnetmvc action 如何简单处理?

  如果你在action中的逻辑需要中断,你可以变通的通过逻辑判断来中断

  比如:

if(ok)
{
    //应有的逻辑
}
else
{
    //中断            
}

//或者

if(!ok)
    return Content("NO");

   但是如果是在过滤器中!

        protected virtual void OnActionExecuted(ActionExecutedContext filterContext);
        protected virtual void OnActionExecuting(ActionExecutingContext filterContext);
        protected virtual void OnAuthorization(AuthorizationContext filterContext);
        protected virtual void OnException(ExceptionContext filterContext);
        protected virtual void OnResultExecuted(ResultExecutedContext filterContext);
        protected virtual void OnResultExecuting(ResultExecutingContext filterContext);

  的 逻辑判断 和 Response.End();  都无效的!

   看到很多人都是用的跳转!如果是aspnet mvc web api,往哪里跳转呢。

正确的aspnet mvc filter Cancel Execution姿势!

  那就是赋值 filterContext.Result!

  例如OnActionExecuting

  protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var headerAuth = filterContext.HttpContext.Request.Headers["_applogin_"];
            if (string.IsNullOrEmpty(headerAuth))
            {
                filterContext.Result = new ContentResult()
                {
                    Content = "{code:9999,message:'no login'}",
                    ContentEncoding = Encoding.UTF8
                };
            }

            base.OnActionExecuting(filterContext);
        }
    }

 

为什么赋值了Context.Result就不会继续执行后面的过滤器和action的代码?

  先看下aspnetmvc源码!

  aspnet mvc 源码:ControllerActionInvoker.cs

using Microsoft.Web.Infrastructure.DynamicValidationHelper;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Web.Mvc.Properties;
namespace System.Web.Mvc
{
	/// <summary>Represents a class that is responsible for invoking the action methods of a controller.</summary>
	public class ControllerActionInvoker : IActionInvoker
	{
		private static readonly ControllerDescriptorCache _staticDescriptorCache = new ControllerDescriptorCache();
		private ModelBinderDictionary _binders;
		private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = new Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>>(FilterProviders.Providers.GetFilters);
		private ControllerDescriptorCache _instanceDescriptorCache;
		/// <summary>Gets or sets the model binders that are associated with the action.</summary>
		/// <returns>The model binders that are associated with the action.</returns>
		protected internal ModelBinderDictionary Binders
		{
			get
			{
				if (this._binders == null)
				{
					this._binders = ModelBinders.Binders;
				}
				return this._binders;
			}
			set
			{
				this._binders = value;
			}
		}
		internal ControllerDescriptorCache DescriptorCache
		{
			get
			{
				if (this._instanceDescriptorCache == null)
				{
					this._instanceDescriptorCache = ControllerActionInvoker._staticDescriptorCache;
				}
				return this._instanceDescriptorCache;
			}
			set
			{
				this._instanceDescriptorCache = value;
			}
		}
		/// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.ControllerActionInvoker" /> class.</summary>
		public ControllerActionInvoker()
		{
		}
		internal ControllerActionInvoker(params object[] filters) : this()
		{
			if (filters != null)
			{
				this._getFiltersThunk = ((ControllerContext cc, ActionDescriptor ad) => 
					from f in filters
					select new Filter(f, FilterScope.Action, null));
			}
		}
		/// <summary>Creates the action result.</summary>
		/// <returns>The action result object.</returns>
		/// <param name="controllerContext">The controller context.</param>
		/// <param name="actionDescriptor">The action descriptor.</param>
		/// <param name="actionReturnValue">The action return value.</param>
		protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
		{
			if (actionReturnValue == null)
			{
				return new EmptyResult();
			}
			ActionResult arg_2B_0;
			if ((arg_2B_0 = (actionReturnValue as ActionResult)) == null)
			{
				arg_2B_0 = new ContentResult
				{
					Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture)
				};
			}
			return arg_2B_0;
		}
		/// <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 controllerType = controllerContext.Controller.GetType();
			return this.DescriptorCache.GetDescriptor(controllerType, () => new ReflectedControllerDescriptor(controllerType));
		}
		/// <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)
		{
			return controllerDescriptor.FindAction(controllerContext, actionName);
		}
		/// <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));
		}
		private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor)
		{
			return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType);
		}
		/// <summary>Gets the value of the specified action-method parameter.</summary>
		/// <returns>The value of the action-method parameter.</returns>
		/// <param name="controllerContext">The controller context.</param>
		/// <param name="parameterDescriptor">The parameter descriptor.</param>
		protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
		{
			Type parameterType = parameterDescriptor.ParameterType;
			IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor);
			IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
			string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
			Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);
			ModelBindingContext bindingContext = new ModelBindingContext
			{
				FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,
				ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
				ModelName = modelName,
				ModelState = controllerContext.Controller.ViewData.ModelState,
				PropertyFilter = propertyFilter,
				ValueProvider = valueProvider
			};
			object obj = modelBinder.BindModel(controllerContext, bindingContext);
			return obj ?? parameterDescriptor.DefaultValue;
		}
		/// <summary>Gets the values of the action-method parameters.</summary>
		/// <returns>The values of the action-method parameters.</returns>
		/// <param name="controllerContext">The controller context.</param>
		/// <param name="actionDescriptor">The action descriptor.</param>
		protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			ParameterDescriptor[] parameters = actionDescriptor.GetParameters();
			ParameterDescriptor[] array = parameters;
			for (int i = 0; i < array.Length; i++)
			{
				ParameterDescriptor parameterDescriptor = array[i];
				dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor);
			}
			return dictionary;
		}
		private static Predicate<string> GetPropertyFilter(ParameterDescriptor parameterDescriptor)
		{
			ParameterBindingInfo bindingInfo = parameterDescriptor.BindingInfo;
			return (string propertyName) => BindAttribute.IsPropertyAllowed(propertyName, bindingInfo.Include.ToArray<string>(), bindingInfo.Exclude.ToArray<string>());
		}
		/// <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))
			{
				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
				{
					AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
					if (authorizationContext.Result != null)
					{
						this.InvokeActionResult(controllerContext, 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);
						this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, 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;
		}
		/// <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);
		}
		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;
		}
		/// <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();
		}
		/// <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);
		}
		internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func<ResultExecutedContext> continuation)
		{
			filter.OnResultExecuting(preContext);
			if (preContext.Cancel)
			{
				return new ResultExecutedContext(preContext, preContext.Result, true, null);
			}
			bool flag = false;
			ResultExecutedContext resultExecutedContext = null;
			try
			{
				resultExecutedContext = continuation();
			}
			catch (ThreadAbortException)
			{
				resultExecutedContext = new ResultExecutedContext(preContext, preContext.Result, false, null);
				filter.OnResultExecuted(resultExecutedContext);
				throw;
			}
			catch (Exception exception)
			{
				flag = true;
				resultExecutedContext = new ResultExecutedContext(preContext, preContext.Result, false, exception);
				filter.OnResultExecuted(resultExecutedContext);
				if (!resultExecutedContext.ExceptionHandled)
				{
					throw;
				}
			}
			if (!flag)
			{
				filter.OnResultExecuted(resultExecutedContext);
			}
			return resultExecutedContext;
		}
		/// <summary>Invokes the specified action result by using the specified action filters and the controller context.</summary>
		/// <returns>The context for the ResultExecuted 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="actionResult">The action result.</param>
		protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult)
		{
			ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult);
			Func<ResultExecutedContext> seed = delegate
			{
				this.InvokeActionResult(controllerContext, actionResult);
				return new ResultExecutedContext(controllerContext, actionResult, false, null);
			};
			Func<ResultExecutedContext> func = filters.Reverse<IResultFilter>().Aggregate(seed, (Func<ResultExecutedContext> next, IResultFilter filter) => () => ControllerActionInvoker.InvokeActionResultFilter(filter, preContext, next));
			return func();
		}
		/// <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;
		}
		/// <summary>Invokes the specified exception filters by using the specified exception and controller context.</summary>
		/// <returns>The context for the <see cref="T:System.Web.Mvc.HandleErrorAttribute" /> object.</returns>
		/// <param name="controllerContext">The controller context.</param>
		/// <param name="filters">The exception filters.</param>
		/// <param name="exception">The exception.</param>
		protected virtual ExceptionContext InvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)
		{
			ExceptionContext exceptionContext = new ExceptionContext(controllerContext, exception);
			foreach (IExceptionFilter current in filters.Reverse<IExceptionFilter>())
			{
				current.OnException(exceptionContext);
			}
			return exceptionContext;
		}
		internal static void ValidateRequest(ControllerContext controllerContext)
		{
			if (controllerContext.IsChildAction)
			{
				return;
			}
			HttpContext current = HttpContext.Current;
			if (current != null)
			{
				ValidationUtility.EnableDynamicValidation(current);
			}
			controllerContext.HttpContext.Request.ValidateInput();
		}
	}
}

 附上简单注释:

        /// <summary>
        /// 执行一个 控制器方法
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="actionName"></param>
        /// <returns></returns>
        public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(actionName))
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
            }
            //根据请求获取控制信息
            ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
            //根据请求和控制器获取action信息
            ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
            //action不为空
            if (actionDescriptor != null)
            {
                //获取或滤器信息
                FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
                try
                {
                    //获取aspnetmvc自带的Authorization信息
                    AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);

                    //这里我们可以看到,在授权的代码里面也可以赋值,当在获取授权时赋值了Result,当前执行会被返回Result,action的代码和过滤器的代码将不会执行
                    if (authorizationContext.Result != null)
                    {
                        this.InvokeActionResult(controllerContext, 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);

                        //开始执行过滤器和action
                        this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, 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;
        }

        //执行过滤器和action

        // System.Web.Mvc.ControllerActionInvoker
        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)
            {
                //执行action
                Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
            };
            //反序filters,以active执行的seed为基础,累加计算filters得到一个 ActionExecutedContext

            //这里面就是重点了,大概的意思是先执行所有过滤器,最后执行active,如果中途过滤器产生了Context.Result,则不会继续执行后面的过滤器和active,
            Func<ActionExecutedContext> func = filters.Reverse<IActionFilter>()
                .Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) =>
                    () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next));
            return func();
        }

        // System.Web.Mvc.ControllerActionInvoker
        internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
        {
            //调用OnActionExecuting
            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
            {
                //真正的执行action
                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;
        }

  从以上代码我们可以看出,一个action的执行流程是这样的:

 

    1>根据请求获取Controller和action的信息

    2>获取应该有的过滤器

    3>Authorization验证,如果不通过则返回

    4>ValidateRequest,验证请求数据

    5>执行过滤器和active,如果在中途过滤器产生Result,则后面的过滤器和active将不会执行!

 

    所以,最正确的方法就是在过滤器中赋值Result!

posted @ 2015-03-18 11:17  0xc  阅读(2268)  评论(1编辑  收藏  举报