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

简介: 原文:ASP.NET Core 2 学习笔记(十四)FiltersFilter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。
原文: 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. \r\n");
        }
    }
}

非同步的方式:

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

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. \r\n");
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

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

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

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. \r\n");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

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

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

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. \r\n");
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

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

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

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. \r\n");
        }
    }
}

非同步的方式:

// ...
public class ExceptionFilter : IAsyncExceptionFilter
{
        public Task OnExceptionAsync(ExceptionContext context)
        {
            context.ExceptionHandled = true;// 表明异常已处理,客户端可得到正常返回
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
            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! \r\n");
        }
        
        [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! \r\n");
        }
        
        [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. \r\n");
    }
    public void OnActionExecuted(ActionExecutedContext context)
    {
        context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) out. \r\n");
    }
}

在注册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! \r\n");
        }
    }
}

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

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  

目录
相关文章
|
8天前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:<https://github.com/khellang/Scrutor>
30 5
|
26天前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
38 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
16天前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
24 3
|
2月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
开发框架 前端开发 .NET
ASP.NET Core 核心特性学习笔记「下」
ASP.NET Core 核心特性学习笔记「下」
|
开发框架 前端开发 中间件
ASP.NET Core 核心特性学习笔记「上」
ASP.NET Core 核心特性学习笔记「上」
|
SQL 机器学习/深度学习 Cloud Native
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
- 状态 - 自动变更检测 - 不查询删除和更新 - 并发
255 0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
|
SQL Cloud Native 架构师
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记
- 关联数据加载 - 客户端与服务端运算 - 跟踪与不跟踪 - 复杂查询运算 - 原生 SQL 查询 - 全局查询筛选器
247 0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记
|
Cloud Native 架构师
|
存储 开发框架 Cloud Native
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记
- 连接字符串 - 异步编程 - 日志 - DbContext池 - 类和配置表 - 属性和列配置 - 并发token - 索引
310 0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记