目錄什么是 AOP ?.Net Core 中 有哪些 AOP 框架?基于 Castle DynamicProxy 實現(xiàn) AOPIOC中使用 Castle DynamicProxy實現(xiàn)事務管理實現(xiàn)用戶自動填充 什么是 AOP ? AOP(Aspect-Oriented Programming,面向切面
AOP(Aspect-Oriented Programming,面向切面編程)是一種編程范式,旨在通過將橫切關注點(cross-cutting concerns)從主要業(yè)務邏輯中分離出來,以提高代碼的模塊化性、可維護性和復用性。
在傳統(tǒng)的面向?qū)ο缶幊讨校覀兺ǔMㄟ^類和對象來組織和實現(xiàn)功能。然而,某些功能,如日志記錄、事務管理、安全性檢查等,可能會跨越多個對象和模塊,這種跨越稱為橫切關注點。AOP 的核心思想是將這些橫切關注點從業(yè)務邏輯中分離出來,通過特定的機制將它們應用到代碼中,而不是通過直接修改業(yè)務邏輯來實現(xiàn)。
PostSharp(收費)
PostSharp是一個功能強大的AOP框架,它通過編譯器插件的形式集成到Visual Studio中。PostSharp支持編譯時AOP(通過C#特性應用切面),并提供了豐富的切面類型,包括方法攔截、屬性訪問攔截、異常處理等。它還提供了商業(yè)支持和豐富的文檔。
Castle DynamicProxy
Castle DynamicProxy是Castle項目的一部分,它允許開發(fā)者在運行時動態(tài)創(chuàng)建代理類,這些代理類可以攔截對目標對象的調(diào)用,并在調(diào)用前后執(zhí)行自定義邏輯。雖然它本身不是一個完整的AOP框架,但它經(jīng)常被用作構(gòu)建AOP解決方案的基礎。
AspectCore Framework
AspectCore 是一個開源的 AOP 框架,專為 .NET Core 設計。它提供了基于動態(tài)代理的運行時切面和方法攔截機制,支持常見的切面編程需求,如日志、緩存、事務等。
1. 安裝Castle.Core NuGet包
Install-Package Castle.Core
2. 定義接口和類
假設你有一個接口和一個實現(xiàn)了該接口的類,你想要攔截這個類的方法調(diào)用。
public interface IMyService
{
void PerformAction();
}
public class MyService : IMyService
{
public void PerformAction()
{
Console.WriteLine("Action performed.");
}
}
3. 創(chuàng)建攔截器
接下來,你需要創(chuàng)建一個攔截器類,該類將實現(xiàn)
IInterceptor
接口。在這個接口的實現(xiàn)中,你可以定義在調(diào)用目標方法之前和之后要執(zhí)行的邏輯。
using Castle.DynamicProxy;
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// 在調(diào)用目標方法之前執(zhí)行的邏輯
Console.WriteLine("Before method: " + invocation.Method.Name);
// 調(diào)用目標方法
invocation.Proceed();
// 在調(diào)用目標方法之后執(zhí)行的邏輯
Console.WriteLine("After method: " + invocation.Method.Name);
}
}
4. 創(chuàng)建代理并調(diào)用方法
最后,你需要使用
ProxyGenerator
類來創(chuàng)建
MyService
的代理實例,并指定攔截器。然后,你可以像使用普通對象一樣調(diào)用代理的方法,但攔截器中的邏輯會在調(diào)用發(fā)生時執(zhí)行。
using Castle.DynamicProxy;
public class Program
{
public static void Main(string[] args)
{
var generator = new ProxyGenerator();
var interceptor = new MyInterceptor();
// 創(chuàng)建MyService的代理實例,并指定攔截器
var proxy = generator.CreateInterfaceProxyWithTarget(
new MyService(), interceptor);
// 調(diào)用代理的方法,攔截器中的邏輯將被執(zhí)行
proxy.PerformAction();
}
}
注意,上面的示例使用了接口代理(
CreateInterfaceProxyWithTarget
),這意味著你的目標類必須實現(xiàn)一個或多個接口。如果你想要代理一個類而不是接口,你可以使用
CreateClassProxyWithTarget
方法(但這通常用于需要代理非虛方法或字段的場景,且要求目標類是可繼承的)。
由于IOC容器(如Microsoft的
IServiceCollection
和
IServiceProvider
)通常不直接支持AOP,所以用
Autofac
1. 安裝必要的 NuGet 包
首先,確保你的項目中安裝了以下 NuGet 包:
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
Install-Package Autofac.Extras.DynamicProxy
Install-Package Castle.Core
2. 創(chuàng)建服務接口和實現(xiàn)類
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public long CreateUserId { get; set; }
public string CreateUserName { get; set; }
public DateTime CreateTime { get; set; }
public long UpdateUserId { get; set; }
public string UpdateUserName { get; set; }
public DateTime UpdateTime { get; set; }
}
public interface IUserService
{
void Test();
Task TaskTest();
void Add(User user);
void Update(User user);
}
public class UserService : IUserService
{
public void Test()
{
Console.WriteLine("Test");
}
public async Task TaskTest()
{
await Console.Out.WriteLineAsync("TaskTest");
return 1;
}
public void Add(User user)
{
Console.WriteLine(user.CreateUserId);
Console.WriteLine(user.CreateUserName);
}
public void Update(User user)
{
Console.WriteLine(user.UpdateUserId);
Console.WriteLine(user.UpdateUserName);
}
}
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
[Route("/taskTest")]
public async Task TaskTest()
{
await _userService.TaskTest();
return "ok";
}
[HttpGet]
[Route("/test")]
public string Test()
{
_userService.Test();
return "ok";
}
[HttpGet]
[Route("/add")]
public string Add()
{
_userService.Add(new Model.User { Name = "張三" });
return "ok";
}
[HttpGet]
[Route("/update")]
public string Update()
{
_userService.Update(new Model.User { Name = "張三" });
return "ok";
}
}
3. 創(chuàng)建攔截器類
創(chuàng)建一個實現(xiàn)
IInterceptor
接口的攔截器類
LoggingInterceptor
,用于攔截方法調(diào)用并添加日志記錄:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Before executing: {invocation.Method.Name}");
invocation.Proceed(); // 調(diào)用原始方法
Console.WriteLine($"After executing: {invocation.Method.Name}");
}
}
4. 配置 Autofac 容器
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //使用Autofac
.ConfigureContainer(autofacBuilder =>
{
autofacBuilder.RegisterType();
autofacBuilder.RegisterType().As ().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors() // 啟用接口攔截器
.InterceptedBy(typeof(LoggingInterceptor)); //指定攔截器
});
與Autofac集成時,配置攔截器主要有兩種方式
使用
InterceptAttribute
特性
這種方式通過在接口或類上添加
[Intercept(typeof(YourInterceptor))]
特性來指定攔截器。然后,在Autofac注冊時,啟用接口或類的攔截器。(通常不推薦在類上直接添加,因為這會使類與Autofac緊密耦合)
[Intercept(typeof(UserAutoFillInterceptor))]
public class UserService : IUserService
{
public void Test()
{
Console.WriteLine("Test");
}
}
autofacBuilder.RegisterType().As().EnableInterfaceInterceptors() // 啟用接口攔截器
使用
InterceptedBy()
方法
這種方式不依賴于
[Intercept]
特性,而是在注冊服務時直接使用
InterceptedBy()
方法來指定攔截器。
autofacBuilder.RegisterType().As()
.EnableInterfaceInterceptors() // 啟用接口攔截器
.InterceptedBy(typeof(LoggingInterceptor)); //指定攔截器
攔截器基類
///
/// 攔截基類
///
///
public abstract class BaseInterceptor : IInterceptor
{
protected readonly ILogger _logger;
public BaseInterceptor(ILogger logger)
{
_logger = logger;
}
///
/// 攔截方法
///
///
public virtual void Intercept(IInvocation invocation)
{
try
{
Method = invocation.MethodInvocationTarget ?? invocation.Method;
InterceptHandle(invocation);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
throw ex;
}
}
///
/// 攔截處理
///
///
public abstract void InterceptHandle(IInvocation invocation);
protected MethodInfo Method{ get; set; }
public static bool IsAsyncMethod(MethodInfo method)
{
return (method.ReturnType == typeof(Task) ||
(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
);
}
}
事務特性:用來判斷是否需要事務管理的
///
/// 事務特性
///
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class TransactionalAttribute : Attribute
{
public TransactionalAttribute()
{
Timeout = 60;
}
///
///
///
public int Timeout { get; set; }
///
/// 事務隔離級別
///
public IsolationLevel IsolationLevel { get; set; }
///
/// 事務傳播方式
///
public Propagation Propagation { get; set; }
}
///
/// 事務傳播方式
///
public enum Propagation
{
///
/// 默認:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中。
///
Required = 0,
///
/// 使用當前事務,如果沒有當前事務,就拋出異常
///
Mandatory = 1,
///
/// 以嵌套事務方式執(zhí)行
///
Nested = 2,
}
事務攔截器:處理事務的
///
/// 事務攔截器
///
public class TransactionalInterceptor : BaseInterceptor
{
public TransactionalInterceptor(ILogger logger) : base(logger)
{
}
public override void InterceptHandle(IInvocation invocation)
{
if (Method.GetCustomAttribute(true) == null && Method.DeclaringType?.GetCustomAttribute(true) == null)
{
invocation.Proceed();
}
else
{
try
{
Console.WriteLine("開啟事務");
//執(zhí)行方法
invocation.Proceed();
// 異步獲取異常,先執(zhí)行
if (IsAsyncMethod(invocation.Method))
{
var result = invocation.ReturnValue;
if (result is Task)
{
Task.WaitAll(result as Task);
}
}
Console.WriteLine("提交事務");
}
catch (Exception ex)
{
Console.WriteLine("回滾事務");
_logger.LogError(ex, ex.Message);
throw ex;
}
}
}
}
接口上加入事務特性
//[Transactional]
public class UserService : IUserService
{
[Transactional]
public void Test()
{
Console.WriteLine("Test");
}
}
注入IOC
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer(autofacBuilder =>
{
autofacBuilder.RegisterType();
autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(TransactionalInterceptor));
});
測試
上下戶用戶
public interface IHttpContextUser
{
long UserId { get; }
string UserName { get;}
}
public class HttpContextUser : IHttpContextUser
{
private readonly IHttpContextAccessor _accessor;
public HttpContextUser(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public long UserId
{
get
{
return 1; //這里暫時是寫死的
if (int.TryParse(_accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Sid), out var userId))
{
return userId;
}
return default;
}
}
public string UserName
{
get
{
return "admin"; //這里暫時是寫死的
return _accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name) ?? "";
}
}
}
注入IOC
builder.Services.AddHttpContextAccessor();
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer(autofacBuilder =>
{
autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces();
autofacBuilder.RegisterType();
autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(UserAutoFillInterceptor));
});
用戶自動攔截器:處理用戶填充的
///
/// 用戶自動填充攔截器
///
public class UserAutoFillInterceptor : BaseInterceptor
{
private readonly IHttpContextUser _user;
public UserAutoFillInterceptor(ILogger logger,IHttpContextUser user) : base(logger)
{
_user = user;
}
public override void InterceptHandle(IInvocation invocation)
{
//對當前方法的特性驗證
if (Method.Name?.ToLower() == "add" || Method.Name?.ToLower() == "update")
{
if (invocation.Arguments.Length == 1 && invocation.Arguments[0].GetType().IsClass)
{
dynamic argModel = invocation.Arguments[0];
var getType = argModel.GetType();
if (Method.Name?.ToLower() == "add")
{
if (getType.GetProperty("CreateUserId") != null)
{
argModel.CreateUserId = _user.UserId;
}
if (getType.GetProperty("CreateUserName") != null)
{
argModel.CreateUserName = _user.UserName;
}
if (getType.GetProperty("CreateTime") != null)
{
argModel.CreateTime = DateTime.Now;
}
}
if (getType.GetProperty("UpdateUserId") != null)
{
argModel.UpdateUserId = _user.UserId;
}
if (getType.GetProperty("UpdateUserName") != null)
{
argModel.UpdateUserName = _user.UserName;
}
if (getType.GetProperty("UpdateTime") != null)
{
argModel.UpdateTime = DateTime.Now;
}
}
invocation.Proceed();
}
else
{
invocation.Proceed();
}
}
}
測試
本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]
湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)