在
ASP.NET Core 中,面向切面编程(AOP)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理、权限验证等)从业务逻辑中分离出来,提高代码的可维护性和可复用性。以下是
ASP.NET Core 中实现 AOP 的几种常见方式:
中间件是
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>() 将其添加到请求处理管道中,实现了日志记录这一横切关注点。
过滤器可以在控制器动作执行的不同阶段插入代码,包括执行前、执行后、异常处理等,常用于实现权限验证、事务管理等功能。
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))] 特性将该过滤器应用到控制器或动作方法上。
使用第三方库如 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 创建代理对象,并将拦截器应用到目标服务上,实现了方法级别的拦截。
全局异常处理可以捕获应用程序中未处理的异常,进行统一的异常处理和日志记录,也是一种 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 中间件捕获应用程序中未处理的异常,进行统一的异常处理和日志记录。