代码改变世界

ASP.NET Core 中AOP的支持有哪些?

2025-03-25 17:29  钟铧若岩  阅读(66)  评论(0)    收藏  举报
ASP.NET Core 中,面向切面编程(AOP)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理、权限验证等)从业务逻辑中分离出来,提高代码的可维护性和可复用性。以下是ASP.NET Core 中实现 AOP 的几种常见方式:

1. 中间件(Middleware)

中间件是ASP.NET Core 请求处理管道的核心组件,可用于在请求处理的不同阶段插入自定义逻辑,是实现 AOP 的一种有效方式。

示例代码

// 自定义中间件类
public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

    public LoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 在请求处理之前记录日志
        Console.WriteLine($"Request received: {context.Request.Path}");

        // 调用下一个中间件
        await _next(context);

        // 在请求处理之后记录日志
        Console.WriteLine($"Request completed: {context.Request.Path}");
    }
}

// 在 Program.cs 中使用中间件
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 使用自定义中间件
app.UseMiddleware<LoggingMiddleware>();

app.MapGet("/", () => "Hello World!");

app.Run();

  

 

代码解释

自定义的 LoggingMiddleware 类在请求处理前后记录日志,通过 app.UseMiddleware<LoggingMiddleware>() 将其添加到请求处理管道中,实现了日志记录这一横切关注点。

2. 过滤器(Filters)

过滤器可以在控制器动作执行的不同阶段插入代码,包括执行前、执行后、异常处理等,常用于实现权限验证、事务管理等功能。

示例代码

using Microsoft.AspNetCore.Mvc.Filters;

// 自定义动作过滤器
public class LoggingActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // 在动作执行之前记录日志
        Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} is about to execute.");
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // 在动作执行之后记录日志
        Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} has executed.");
    }
}

// 在控制器中使用过滤器
[ApiController]
[Route("[controller]")]
[TypeFilter(typeof(LoggingActionFilter))]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("This is a sample action.");
    }
}

  

代码解释

LoggingActionFilter 类实现了 IActionFilter 接口,在控制器动作执行前后记录日志。通过 [TypeFilter(typeof(LoggingActionFilter))] 特性将该过滤器应用到控制器或动作方法上。

3. 依赖注入和拦截器(使用第三方库)

使用第三方库如 Castle DynamicProxy 结合依赖注入可以实现方法级别的拦截,从而实现 AOP。

示例代码

首先,安装 Castle.Core NuGet 包。
using Castle.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;

// 定义服务接口
public interface IMyService
{
    void DoSomething();
}

// 实现服务接口
public class MyService : IMyService
{
    public void DoSomething()
    {
        Console.WriteLine("Doing something...");
    }
}

// 定义拦截器
public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // 在方法调用之前记录日志
        Console.WriteLine($"Method {invocation.Method.Name} is about to be called.");

        // 调用目标方法
        invocation.Proceed();

        // 在方法调用之后记录日志
        Console.WriteLine($"Method {invocation.Method.Name} has been called.");
    }
}

// 在 Program.cs 中配置依赖注入和拦截器
var builder = WebApplication.CreateBuilder(args);

// 创建代理生成器
var proxyGenerator = new ProxyGenerator();

// 注册服务和拦截器
builder.Services.AddScoped<IMyService>(provider =>
{
    var service = new MyService();
    var interceptor = provider.GetRequiredService<LoggingInterceptor>();
    return proxyGenerator.CreateInterfaceProxyWithTarget<IMyService>(service, interceptor);
});
builder.Services.AddScoped<LoggingInterceptor>();

var app = builder.Build();

// 在控制器中使用服务
app.MapGet("/", (IMyService service) =>
{
    service.DoSomething();
    return "Service method called.";
});

app.Run();

  

代码解释

LoggingInterceptor 类实现了 IInterceptor 接口,在方法调用前后记录日志。通过 ProxyGenerator 创建代理对象,并将拦截器应用到目标服务上,实现了方法级别的拦截。

4. 全局异常处理

全局异常处理可以捕获应用程序中未处理的异常,进行统一的异常处理和日志记录,也是一种 AOP 的应用场景。

示例代码

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 全局异常处理
app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = 500;
        context.Response.ContentType = "text/plain";
        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        if (exceptionHandlerPathFeature?.Error != null)
        {
            // 记录异常信息
            Console.WriteLine($"An error occurred: {exceptionHandlerPathFeature.Error.Message}");
            await context.Response.WriteAsync("An error occurred. Please try again later.");
        }
    });
});

app.MapGet("/", () =>
{
    throw new Exception("This is a sample exception.");
});

app.Run();

  

代码解释

通过 app.UseExceptionHandler 中间件捕获应用程序中未处理的异常,进行统一的异常处理和日志记录。