C# Mediatr管道行为中如何获取Command Handler的自定义Attribute
实现方案
核心思路
Mediatr中每个TRequest对应的IRequestHandler<TRequest, TResponse>实现都已经注册到DI容器,我们可以通过注入的IServiceProvider获取到实际的Handler实例,再读取其类上的特性即可。
完整代码实现
1. 首先定义事务特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class SqlTransactionAttribute : Attribute { // 可按需扩展事务级别等参数 public IsolationLevel IsolationLevel { get; set; } = IsolationLevel.ReadCommitted; }
2. 实现TransactionBehavior
public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull { private readonly IServiceProvider _serviceProvider; // 注入你的数据库上下文,这里以EF Core的AppDbContext为例 private readonly AppDbContext _dbContext; public TransactionBehavior(IServiceProvider serviceProvider, AppDbContext dbContext) { _serviceProvider = serviceProvider; _dbContext = dbContext; } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { // 获取当前请求对应的Handler实例 var handler = _serviceProvider.GetService<IRequestHandler<TRequest, TResponse>>(); if (handler == null) { return await next(); } // 无装饰器场景可以直接用handler.GetType(),有装饰器需要先解包 var handlerType = handler.GetType(); // 如果你使用了Scrutor等工具做Handler装饰器,用下面的方法解包获取实际业务Handler类型 // handlerType = UnwrapDecoratorType(handler.GetType()); // 判断Handler类上是否标记了事务特性 if (!Attribute.IsDefined(handlerType, typeof(SqlTransactionAttribute))) { return await next(); } // 开启事务执行逻辑 using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken); try { var response = await next(); await _dbContext.SaveChangesAsync(cancellationToken); await transaction.CommitAsync(cancellationToken); return response; } catch { await transaction.RollbackAsync(cancellationToken); throw; } } // 装饰器解包辅助方法,按需使用 private Type UnwrapDecoratorType(Type currentType) { var constructors = currentType.GetConstructors(); foreach (var constructor in constructors) { var parameters = constructor.GetParameters(); if (parameters.Any(p => p.ParameterType == typeof(IRequestHandler<TRequest, TResponse>))) { var innerInstance = constructor.Invoke(parameters.Select(p => _serviceProvider.GetService(p.ParameterType)).ToArray()) as IRequestHandler<TRequest, TResponse>; return UnwrapDecoratorType(innerInstance!.GetType()); } } return currentType; } }
注册和使用
- 先在DI容器中注册Behavior:
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(TransactionBehavior<,>));
- 直接在需要加事务的Command Handler类上标记特性即可:
[SqlTransaction(IsolationLevel = IsolationLevel.Serializable)] public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, long> { // 业务逻辑实现 }
内容的提问来源于stack exchange,提问作者Shervin Ivari
相关产品推荐
相关产品推荐

