• ASP.NET Core 2 学习笔记(十四)Filters


    Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization FilterResource FilterAction FilterException FilterResult Filter
    通过不同的Filter可以有效处理封包进出的加工,本篇将介绍ASP.NET Core的五种Filter运作方式。

    Filter 介绍

    Filter的作用是在Action 执行前或执行后做一些加工处理。
    某种程度来看,会跟Middleware很像,但执行的顺序略有不同,用对Filter不仅可以减少代码,还可以提高执行效率。

    ASP.NET Core 有以下五种Filter 可以使用:

    • Authorization Filter
      Authorization是五种Filter中优先级最高的,通常用于验证Request合不合法,不合法后面就直接跳过。
    • Resource Filter
      Resource是第二优先,会在Authorization之后,Model Binding之前执行。通常会是需要对Model加工处理才用。
    • Action Filter
      最常使用的Filter,封包进出都会经过它,使用上没什么需要特别注意的。跟Resource Filter很类似,但并不会经过Model Binding。
    • Exception Filter
      异常处理的Filter。
    • Result Filter
      当Action完成后,最终会经过的Filter。

    Filter 运作方式

    ASP.NET Core的每个Request都会先经过已注册的Middleware接着才会执行Filter,除了会依照上述的顺序外,同类型的Filter预设都会以先进后出的方式处里封包。
    Response在某些Filter并不会做处理,会直接被pass。Request及Response的运作流程如下图:

    • 黄色箭头是正常情况流程
    • 灰色箭头是异常处理流程

    建立Filter

    ASP.NET Core的Filter基本上跟ASP.NET MVC的差不多。
    上述的五种Filter范例分别如下:

    Authorization Filter

    AuthorizationFilter.cs

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace MyWebsite.Filters
    {
        public class AuthorizationFilter : IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
            }
        }
    }
    

    非同步的方式:

    // ...
    public class AuthorizationFilter : IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
        }
    }
    

    Resource Filter

    ResourceFilter.cs

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace MyWebsite.Filters
    {
        public class ResourceFilter : IResourceFilter
        {
            public void OnResourceExecuting(ResourceExecutingContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
            }
    
            public void OnResourceExecuted(ResourceExecutedContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
            }
        }
    }
    

    非同步的方式:

    // ...
    public class ResourceFilter : IAsyncResourceFilter
    {
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
    
            await next();
    
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
        }
    }
    

    Action Filter

    ActionFilter.cs

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace MyWebsite.Filters
    {
        public class ActionFilter : IActionFilter
        {
            public void OnActionExecuting(ActionExecutingContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
            }
    
            public void OnActionExecuted(ActionExecutedContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
            }
        }
    }
    

    非同步的方式:

    // ...
    public class ActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
    
            await next();
    
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
        }
    }
    

    Result Filter

    ResultFilter.cs

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace MyWebsite.Filters
    {
        public class ResultFilter : IResultFilter
        {
            public void OnResultExecuting(ResultExecutingContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
            }
    
            public void OnResultExecuted(ResultExecutedContext context)
            {
                context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
            }
        }
    }
    

    非同步的方式:

    // ...
    public class ResultFilter : IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
    
            await next();
    
            await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. 
    ");
        }
    }
    

    Exception Filter

    ExceptionFilter.cs

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace MyWebsite.Filters
    {
        public class ExceptionFilter : IExceptionFilter
        {
            public void OnException(ExceptionContext context)
            {
                context.ExceptionHandled = true; // 表明异常已处理,客户端可得到正常返回
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
            }
        }
    }
    

    非同步的方式:

    // ...
    public class ExceptionFilter : IAsyncExceptionFilter
    {
            public Task OnExceptionAsync(ExceptionContext context)
            {
                context.ExceptionHandled = true;// 表明异常已处理,客户端可得到正常返回
                context.HttpContext.Response.WriteAsync($"{GetType().Name} in. 
    ");
                return Task.CompletedTask;
            }
    }
    

    注册Filter

    Filter有两种注册方式,一种是全局注册,另一种是用[Attribute]局部注册的方式,只套用在特定的Controller或Action。

    全局注册

    Startup.ConfigureServices的MVC服务中注册Filter,这样就可以套用到所有的Request。如下:

    // ...
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(config =>
            {
                config.Filters.Add(new ResultFilter());
                config.Filters.Add(new ExceptionFilter());
                config.Filters.Add(new ResourceFilter());
            });
        }
    }
    

    局部注册

    ASP.NET Core在局部注册Filter的方式跟ASP.NET MVC有一点不一样,要通过[TypeFilter(type)]
    在Controller或Action上面加上[TypeFilter(type)]就可以局部注册Filter。如下:

    // ...
    namespace MyWebsite.Controllers
    {
        [TypeFilter(typeof(AuthorizationFilter))]
        public class HomeController : Controller
        {
            [TypeFilter(typeof(ActionFilter))]
            public void Index()
            {
                Response.WriteAsync("Hello World! 
    ");
            }
            
            [TypeFilter(typeof(ActionFilter))]
            public void Error()
            {
                throw new System.Exception("Error");
            }
        }
    }
    

    [TypeFilter(type)]用起来有点冗长,想要像过去ASP.NET MVC用[Attribute]注册Filter的话,只要将Filter继承Attribute即可。如下:

    public class AuthorizationFilter : Attribute, IAuthorizationFilter
    {
        // ...
    }
    public class ActionFilter : Attribute, IActionFilter
    {
        // ...
    }
    

    [Attribute] 注册就可以改成如下方式:

    // ...
    namespace MyWebsite.Controllers
    {
        [AuthorizationFilter]
        public class HomeController : Controller
        {
            [ActionFilter]
            public void Index()
            {
                Response.WriteAsync("Hello World! 
    ");
            }
            
            [ActionFilter]
            public void Error()
            {
                throw new System.Exception("Error");
            }
        }
    }
    

    执行结果

    http://localhost:5000/Home/Index 输出结果如下:

    AuthorizationFilter in.
    ResourceFilter in.
    ActionFilter in.
    Hello World!
    ActionFilter out.
    ResultFilter in.
    ResultFilter out.
    ResourceFilter out.
    

    http://localhost:5000/Home/Error 输出结果如下:

    AuthorizationFilter in.
    ResourceFilter in.
    ActionFilter in.
    ActionFilter out.
    ExceptionFilter in.
    ResourceFilter out.
    

    执行顺序

    预设注册同类型的Filter 是以先进后出的方式处里封包,注册层级也会影响执行顺序。

    但也可以通过实现 IOrderedFilter 更改执行顺序。例如:

    public class ActionFilter : Attribute, IActionFilter, IOrderedFilter
    {
        public string Name { get; set; }
    
        public int Order { get; set; } = 0;
    
        public void OnActionExecuting(ActionExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) in. 
    ");
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) out. 
    ");
        }
    }
    

    在注册Filter 时带上Order,数值越小优先权越高。

    // ...
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(config =>
            {
                config.Filters.Add(new ActionFilter() { Name = "Global", Order = 3 });
            });
        }
    }
    
    // ...
    namespace MyWebsite.Controllers
    {
        [ActionFilter(Name = "Controller", Order = 2)]
        public class HomeController : Controller
        {
            [ActionFilter(Name = "Action", Order = 1)]
            public void Index()
            {
                Response.WriteAsync("Hello World! 
    ");
            }
        }
    }
    

    变更执行顺序后的输出内容:

    ActionFilter(Action) in. 
    ActionFilter(Controller) in. 
    ActionFilter(Global) in. 
    Hello World! 
    ActionFilter(Global) out. 
    ActionFilter(Controller) out. 
    ActionFilter(Action) out.
    

    参考

    ASP.NET Core Filters

    老司机发车啦:https://github.com/SnailDev/SnailDev.NETCore2Learning  

  • 相关阅读:
    14GDB代码反向执行
    AcWing 1144. 连接格点
    AcWing 1143. 联络员
    AcWing 1141 局域网
    AcWing 1148 秘密的牛奶运输
    AcWing 904 虫洞
    AcWing 1146. 新的开始  
    AcWing 1140. 最短网络
    AcWing 346 走廊泼水节
    AcWing 1145. 北极通讯网络
  • 原文地址:https://www.cnblogs.com/snaildev/p/9154669.html
Copyright © 2020-2023  润新知