.net core AOP

AOP,即面向切面编程,可以在不修改源代码的情况下,为程序动态地添加功能。通过横切技术,将影响多个类的公共行为(如日志记录、性能统计、安全控制、异常处理、事务处理等)封装到一个可重用的模块中。以此来减少系统的重复代码,降低模块的耦合度,提高程序的可重用性、可操作性和可维护性。

AOP在.NET Core中的应用场景非常广泛,包括但不限于:

  • 日志记录:记录系统运行的详细信息,便于问题追踪和性能分析。
  • 性能统计:监控和统计方法的执行时间,帮助开发者优化系统性能。
  • 安全控制:进行身份验证和授权,确保系统安全。
  • 事务处理:管理数据库事务,确保数据的一致性和完整性。
  • 异常处理:全局捕获和处理异常,避免程序崩溃,并记录异常信息以便后续分析。

一、过滤器 Filter

过滤器(Filter)

  • Authorization Filter:用于身份验证和授权,是五种Filter中优先级最高的。
  • Resource Filter:在Action执行前后进行资源处理,如资源缓存、防盗链等。
  • Exception Filter:用于全局的异常处理,捕获并处理未捕获的异常。
  • Action Filter:在Action执行前后进行拦截,常用于执行操作日志、参数验证等。
  • Result Filter:在Action结果返回前后进行拦截,常用于对结果进行格式化、大小写转换等操作。
1、五大常用Filter

1.1、Authorization Filter

权限控制过滤器 通过 Authonization Filter 可以实现复杂的权限角色认证登陆授权等操作

public class AuthonizationFilter :Attribute,IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //这里可以做复杂的权限控制操作
            if (context.HttpContext.User.Identity.Name != "1") //简单的做一个示范
            {
                //未通过验证则跳转到无权限提示页
                RedirectToActionResult content = new RedirectToActionResult("NoAuth", "Exception", null);
                context.Result = content;
            }
        }
    }

1.2、Resource Filter

资源过滤器 可以通过Resource Filter 进行资源缓存防盗链等操作

public class ResourceFilter : Attribute,IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            // 执行完后的操作
        }
 
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            // 执行中的过滤器管道
        }
    }

1.3、Exception Filter

通过Execption Filter 过滤器可以进行全局的异常日志收集 等操作。

public class ExecptionFilter : Attribute, IExceptionFilter
  {
        private ILogger<ExecptionFilter> _logger;
        //构造注入日志组件
        public ExecptionFilter(ILogger<ExecptionFilter> logger)
        {
            _logger = logger;
        }
 
        public void OnException(ExceptionContext context)
        {
            //日志收集
            _logger.LogError(context.Exception, context?.Exception?.Message??"异常");
        }
    }

1.4、Action Filter

可以通过ActionFilter 拦截 每个执行的方法进行一系列的操作,比如:执行操作日志参数验证权限控制 等一系列操作

public class ActionFilter : Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            //执行完成....
        }
 
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //执行中...
        }
    }

1.5、Result Filter

结果过滤器,可以对结果进行格式化、大小写转换等一系列操作。

public class ResultFilter : Attribute, IResultFilter
 {
        public void OnResultExecuted(ResultExecutedContext context)
        { 
            // 在结果执行之后调用的操作...
        }
 
        public void OnResultExecuting(ResultExecutingContext context)
        {
            // 在结果执行之前调用的一系列操作
        }
    }

2、过滤器的注册方式

全局:将作用于所有请求的action
controller:将作用于这个controller下的所有action
action:作用于单个action

2.1、全局注册

builder.Services.AddMvc(options =>
{
    options.Filters.Add<FilterAttribute>();
});

2.2、Controller 注册方式

[Route("api/[controller]")]
    [ApiController]
    [Filter]//添加过滤器特性,该控制器的所有方法自动走该过滤器
    public class FilterAttributeController : ControllerBase
    {

        [HttpGet]
        [Filter]//添加过滤器特性,该方法自动走该过滤器
        public string G_Method1()
        {
            return "1";
        }

    }

2.3、Action 注册方式

如2.2

3、TypeFilter 和 ServiceFilter

3.1、ServiceFilter

通过ServiceFilter从容器中检索你的ActionFilter,并且注入到需要的地方。

	 //在Program.cs中必须先注册MyFilter这个过滤器到服务容器中
	 builder.Services.AddSigleton<MyFilter>();

    //控制器方法上用ServiceFilter注入自定义过滤器
    [ServiceFilter(typeof(MyFilter))]
    public IActionResult Index()
    {
        //一些处理 
        ...
        return Ok();
    }

3.2、TypeFilter

使用Microsoft.Extensions.DependencyInjection.ObjectFactory 对类型进行实例化。

    //控制器方法上用TypeFilter注入自定义过滤器
    [TypeFilter(typeof(MyFilter),IsReusable = true)]
    public IActionResult Index()
    {
        //一些处理 
        ...
        return Ok();
    }

它和ServiceFilter的区别是它不从DI容器中创建实例,所以不需要在服务容器中进行注册就能使用。TypeFilter是通过ObjectFactory来创建实例的,ObjectFactory是ActivatorUtilities.CreateFactory创建出来的委托。

ServiceFilter与TypeFilter总结

这两个特性都可以实现自定义过滤器的局部注入,但有不同:

ServiceFilter和TypeFilter都实现了IFilterFactory
ServiceFilter需要对自定义的Filter进行注册,TypeFilter不需要
ServiceFilter的Filter生命周期源自于您如何注册,而TypeFilter每次都会创建一个新的实例

4、Filter特性

4.1、内置的过滤器特性
以下列举部分常见的内置过滤器特性,我们可以通过继承这些类,快速实现自己的特性类。

ActionFilterAttribute :行为过滤器特性
ExceptionFilterAttribute:异常过滤器特性
ResultFilterAttribute:结果过滤器特性
FormatFilterAttribute:响应格式化过滤器特性
ServiceFilterAttribute:用来局部使用过滤器的特性
TypeFilterAttribute:也是用来局部注入过滤器的特性

4.2、 编写一个过滤器特性

使用ActionFilterAttribute这个内置过滤器特性,自定义一个过滤器特性,来实现添加任意响应头部信息

 /// <summary>
 /// 继承了一个 ActionFilterAttribute,这个抽象类继承了什么接口呢?
 /// </summary>
 //ResponseHeaderAttribute是一个自定义特性,[ResponseHeader]
 public class ResponseHeaderAttribute : ActionFilterAttribute  
 {
     private readonly string _name;
     private readonly string _value;

     /// <summary>
     /// 构造函数
     /// </summary>
     /// <param name="name"></param>
     /// <param name="value"></param>
     public ResponseHeaderAttribute(string name, string value)
     {
         (_name, _value) = (name, value); //元组赋值法
     }
         
     /// <summary>
     /// 结果过滤器里边的 结果被执行前
     /// </summary>
     /// <param name="context"></param>
     public override void OnResultExecuting(ResultExecutingContext context)
     {
         //添加响应头,键值对信息  (你对HTTP协议了解多少??)
         context.HttpContext.Response.Headers.Add(_name, _value);
         base.OnResultExecuting(context);
     }
 }

测试以上定义的自定义过滤器

//在控制器上应用
[ResponseHeader("Filter-Header", "Filter Value")]
public class UserController : ControllerBase
{
    public IActionResult Index() =>
        Content("请通过浏览器F12调试工具查看输出的响应头信息");
    // ...
	
    //也可以在方法上面应用
    [ResponseHeader("Another-Filter-Header", "Another Filter Value")]
    public IActionResult Multiple() =>
        Content("请通过浏览器F12调试工具查看输出的响应头信息");
}

二、中间件 Middleware

1、概念

中间件是一种处理HTTP请求和响应的独立组件,它位于客户端请求与服务器端处理程序之间。每个中间件组件负责执行特定任务,并可以选择将请求传递给管道中的下一个中间件,直至请求被最终处理或响应被返回给客户端。

执行流程

2、Map、Use 和 Run

Map 用来定义一个管道可以处理哪些请求,Use 和 Run 用来定义管道,一个管道由若干个 Use 和一个 Run 组成,每个 Use 引入一个中间件,而 Run 用来执行最终的核心应用逻辑。

2.1、使用use添加中间件

//使用use添加单个中间件
app.Use(async (context, next) =>
{
    context.Request.Headers.Add("head1", "11");
    await next.Invoke();
    Console.WriteLine(context.Request.Headers["head1"]);
    Console.WriteLine("22");
});

2.2、使用map匹配对应路由的中间件

//使用map为指定路由的action添加中间件,以下就是一个管道
app.Map("/api/FilterAttribute/test1", appbuilders =>
{
    //第一个中间件
    appbuilders.Use(async (context, next) =>
    {
        context.Request.Headers.Add("head3", "33");
        await next.Invoke();
        Console.WriteLine(context.Request.Headers["head3"]);
        Console.WriteLine("44");
    });
    //第二个中间件
    appbuilders.Use(async (context, next) =>
    {
        context.Request.Headers.Add("head5", "55");
        await next.Invoke();
        Console.WriteLine(context.Request.Headers["head5"]);
        Console.WriteLine("66");
    });

    //第三个中间件,也是终止
    appbuilders.Run(async context =>
    {
        Console.WriteLine("/FilterAttribute这个路径下的中间件结束了");
    });
});

当执行时/api/FilterAttribute下的test1方法时,打印如下

/FilterAttribute这个路径下的中间件结束了
55
66
33
44

注://如果在一个中间件中使用 ctx.Response.WriteAsync 向客户端发送响应,就不能再执行 next.Invoke 把请求转到其他中间件了,因为其他中间件中有可能对 Response 进行了更改,比如修改响应状态码、修改报文头或者向响应报文中写入其他数据, 这样就会造成响应报文体被损坏的问题,如果在向报文体中写入内容后,又执行 next.Invoke 是不推荐的行为

2.3、使用MapWhen判断是否执行中间件

app.MapWhen(context =>
{
    return 1 == 1;//如果返回true,则执行下面的中间件
}, appbuilder =>
{
    appbuilder.Use(async (context, next) =>
    {
        Console.WriteLine("77");
        await next.Invoke();
        Console.WriteLine("88");
    });
    appbuilder.Run(async context =>
    {
        Console.WriteLine("77");
    });
});

3、自定义中间件
public class MyMiddleware1
    {
        //需要有RequestDelegate、InvokeAsync方法参数是HttpContext类型
        private readonly RequestDelegate _requestDelegate;
        public MyMiddleware1(RequestDelegate requestDelegate)
        {
            _requestDelegate = requestDelegate;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            Console.WriteLine("MyMiddleware1执行前");
            await _requestDelegate.Invoke(context);
            Console.WriteLine("MyMiddleware1执行后");
        }

    }

//在program.cs中
app.UseMiddleware<MyMiddleware1>();

4、常用内置中间件
中间件名称英文名称作用
身份验证中间件UseAuthentication提供身份验证支持
异常处理中间件UseExceptionHandler异常/错误处理
跨域中间件UseCors配置跨域资源共享
路由中间件UseRouting定义和约束请求路由
静态文件中间件UseStaticFiles为静态文件和目录浏览提供服务提供支持
授权中间件UseAuthorization用于授权用户访问安全资源
终结点路由中间件UseEndpoints定义和约束请求路由,用于匹配路由的终端

此外,还有Session会话,Cookie,响应缓存等中间件。

中间件顺序

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值