Autofac 通用装饰器未被触发(使用 mediatr)

Autofac generic decorator not fired (with mediatr)

我在使用我的通用装饰器时遇到了问题,并且找不到关于我所查看的任何主题的解决方案。我想我很接近,但我错过了一些东西。

为了简化,我在 .NetCore 中有一个 API,在 .Net Standard 中有一个模块。我想在 .Net Standard 中管理模块的 DI,API 只需在 Startup.

中调用它

在Program.cs中,我使用autofac服务提供者工厂

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder => webBuilder
            .UseStartup<Startup>()
            .UseSerilog()
        )
        .UseServiceProviderFactory(new AutofacServiceProviderFactory());
}

在我的 Startup.cs 中,我有 ConfigureContainer 初始化我的模块

public void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterModule(new MyModuleAutofacModule());

    MyModuleStartup.Initialize();
}

在我的模块启动中,我注册了我的子模块、类型...

public static void Initialize()
{
    var containerBuilder = new ContainerBuilder();

    containerBuilder.AddMediatR(typeof(StudiDropboxModule).Assembly);
    containerBuilder.RegisterModule(new ProcessingModule());
    ...
    
    containerBuilder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .Where(t => t.Name.EndsWith("Handler"))
        .AsImplementedInterfaces();

    containerBuilder.RegisterGenericDecorator(
        typeof(LoggingCommandHandlerDecorator<>),
        typeof(ICommandHandler<>));
}

Command/Command 处理程序继承自 Mediatr

public interface ICommand : IRequest
{
}

public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand> where TCommand : ICommand
{
}

我的Command/Command处理程序

public class ExampleCommand : ICommand
{
    ...
}

internal class ExampleCommandHandler : ICommandHandler<ExampleCommand>
{
    public async Task<Unit> Handle(ExampleCommand request, CancellationToken cancellationToken)
    {
        ...

        return Unit.Value;
    }
}

装饰者

internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T> where T : ICommand
{
    private readonly ICommandHandler<T> _decorated;

    public LoggingCommandHandlerDecorator(ICommandHandler<T> decorated)
    {
        _decorated = decorated;
    }

    public async Task<Unit> Handle(T command, CancellationToken cancellationToken)
    {
        var result = await _decorated.Handle(command, cancellationToken);

        return result;
    }
}

当我用 mediatr 调用我的命令时,装饰器没有被触发。

当我调用命令时 Mediatr 已解决

internal static async Task Execute(ICommand command)
{
    using (var scope = MyModuleCompositionRoot.BeginLifetimeScope())
    {
        var mediator = scope.Resolve<IMediator>();
        await mediator.Send(command);
    }
}

我想我错过了 autofac 的一些东西。

提前致谢。

MediatR 使用 IRequestHandler 抽象。这意味着 IMediator 实现在内部要求容器提供特定的 IRequestHandler<T>

另一方面,您从 IRequestHandler<T> 派生了一个 ICommandHandler<T>,并在此基础上实现了装饰器。然而,Autofac(以及大多数 DI 容器)将无法将请求的 IRequestHandler<T> 包装在另一个接口的装饰器中。这与 Autofac 的设置方式有关。

要解决您的问题,有以下几种解决方案:

  1. 删除自定义 ICommandHandler<T> 抽象。它似乎毫无用处,只会使您的申请复杂化。
  2. 将默认的 IMediator 实现替换为解析 ICommandHandler<T> 抽象的实现。
  3. 创建一个(通用的)IRequestHandler<T> 代理,将调用转发到包装的 ICommandHandler<T>
  4. 完全放弃 MediatR。

我遇到了同样的问题。

真的很难弄清楚如何在 MediatR 和 Autofac v5 和 v6 中注册装饰器。

所以我创建了一个示例存储库,它描述了如何在最新版本的 Autofac 和 MediatR 中实现清晰的请求、命令和查询处理:github.com/LeftTwixWand/ModernCQRS

示例输出: