首页
/ MediatR中泛型行为注册的最佳实践

MediatR中泛型行为注册的最佳实践

2025-05-20 05:55:05作者:韦蓉瑛

概述

在.NET开发中,MediatR是一个非常流行的中介者模式实现库,它简化了请求/响应、命令、查询、通知和事件的传递过程。本文将重点探讨如何在MediatR中正确注册泛型行为(Generic Behavior),特别是针对异常处理的场景。

泛型行为的基本结构

一个典型的MediatR泛型行为通常继承自IPipelineBehavior<TRequest, TResponse>接口,用于在请求处理管道中插入自定义逻辑。以下是一个常见的异常处理行为实现:

public class UnhandledExceptionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
    where TResponse : BaseResponse
{
    private readonly ILogger<UnhandledExceptionBehavior<TRequest, TResponse>> _logger;

    public UnhandledExceptionBehavior(ILogger<UnhandledExceptionBehavior<TRequest, TResponse>> logger)
    {
        _logger = logger;
    }

    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        try
        {
            return await next();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled Exception for Request {Name} {@Request}", typeof(TRequest).Name, request);

            var response = Activator.CreateInstance<TResponse>();
            response.IsSuccess = false;
            response.ErrorMessage = $"An error occurred while processing your request: {ex.Message}";

            return response;
        }
    }
}

行为注册的常见问题

许多开发者在注册泛型行为时会遇到行为未被调用的问题。这通常是由于注册方式不正确导致的。以下是几种常见的错误注册方式:

  1. 错误的泛型参数指定
cfg.AddBehavior<IPipelineBehavior<IAppRequest<BaseResponse>,BaseResponse>, UnhandledExceptionBehavior<IAppRequest<BaseResponse>, BaseResponse>>();
  1. 分离注册但未使用正确方法
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehavior<,>));

正确的注册方式

方法一:使用AddOpenBehavior

对于泛型行为,应该使用AddOpenBehavior方法进行注册:

builder.Services.AddMediatR(cfg => {
    cfg.RegisterServicesFromAssemblies(typeof(Program).Assembly);
    cfg.AddOpenBehavior(typeof(UnhandledExceptionBehavior<,>));
});

方法二:使用Autofac容器

如果需要更灵活的泛型注册,可以考虑使用Autofac容器:

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
    builder.RegisterSource(new ContravariantRegistrationSource());
    builder.RegisterGeneric(typeof(UnhandledExceptionBehavior<,>)).AsImplementedInterfaces();
});

请求与响应的设计考量

为了确保行为能够正确匹配请求,需要注意请求和响应的设计:

  1. 请求接口:如果使用自定义请求接口,需要确保它继承自IRequest<TResponse>
public interface IAppRequest<T> : IRequest<T>
{
}
  1. 请求实现
public sealed record GetTopQuestionsQry : IAppRequest<GetTopQuestionsQryResult>;
  1. 响应基类
public sealed record GetTopQuestionsQryResult : BaseResponse
{
    public List<QuestionDto> Questions { get; set; }
}

最佳实践建议

  1. 明确行为适用范围:在定义行为时,通过泛型约束明确指定适用的请求和响应类型
  2. 优先使用开放泛型注册AddOpenBehavior是最简洁的泛型行为注册方式
  3. 考虑行为执行顺序:MediatR行为的执行顺序与注册顺序相同,需要合理安排
  4. 日志记录:在行为中加入适当的日志记录,便于调试和问题追踪
  5. 异常处理:在全局异常处理行为中,确保不会泄露敏感信息

通过遵循这些实践,可以确保MediatR中的泛型行为能够正确注册并按预期工作,为应用程序提供强大的管道处理能力。

登录后查看全文
热门项目推荐