ASPNET Core ActionFilterAttribute中断后续请求

转载自:https://www.cnblogs.com/luconsole/p/4346669.html

 

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

感觉是这样?

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
//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");
复制代码

   但是如果是在过滤器中!

1
2
3
4
5
6
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

 附上简单注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/// <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<stringobject> 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<stringobject> parameters)
{
    ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
    Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, falsenull)
    {
        //执行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, truenull)
        {
            Result = preContext.Result
        };
    }
    bool flag = false;
    ActionExecutedContext actionExecutedContext = null;
    try
    {
        //真正的执行action
        actionExecutedContext = continuation();
    }
    catch (ThreadAbortException)
    {
        actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, falsenull);
        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 @ 2022-09-29 11:03  誓鼎  阅读(252)  评论(0编辑  收藏  举报