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!