You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 23:57:00