简体   繁体   中英

Autofac generic decorator not fired (with mediatr)

I have trouble with my generic decorator and can not find a solution on any topic I have looked. I Think I'm close but I miss something.

To simplify, I have an API in.NetCore and a module in.Net Standard. I want to manage the DI for the module in the.Net Standard and the API just call it in Startup.

In Program.cs, I use the autofac service provider factory

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

In my Startup.cs, I have the ConfigureContainer who initialize my modules

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

    MyModuleStartup.Initialize();
}

In my module startup, I register my submodules, types, ...

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 handler inherit from Mediatr

public interface ICommand : IRequest
{
}

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

My Command/CommandHandler

public class ExampleCommand : ICommand
{
    ...
}

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

        return Unit.Value;
    }
}

The decorator

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;
    }
}

When I call my command with mediatr, the decorator is not fired.

Mediatr is resolved when I call a command

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

I think I miss something with autofac.

Thanks in advance.

MediatR makes use of the IRequestHandler abstraction. This means that the IMediator implementation internally asks for a specific IRequestHandler<T> from the container.

You, on the other hand, derived an ICommandHandler<T> from that IRequestHandler<T> , and implemented decorators on top of that. Autofac (and most DI Containers for that matter), however, will not be able to wrap a requested IRequestHandler<T> in a decorator for another interface. That has to do with the way Autofac is set up.

To solve your problem, there are a few solutions:

  1. Remove the custom ICommandHandler<T> abstraction. It seems to serve no purpose and only complicates your application.
  2. Replace the default IMediator implementation with one that resolves ICommandHandler<T> abstractions instead.
  3. Create a (generic) IRequestHandler<T> proxy that forward the call to a wrapped ICommandHandler<T> .
  4. Ditch MediatR completely.

I had the same issue.

It was really difficult to figure, how to register decorators in the MediatR and Autofac v5 and v6.

So I've created a sample repository, that describes how to implement clear requests, commands and queries processing in the latest versions of Autofac and MediatR: github.com/LeftTwixWand/ModernCQRS

The sample output:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM