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:
ICommandHandler<T>
abstraction. It seems to serve no purpose and only complicates your application.IMediator
implementation with one that resolves ICommandHandler<T>
abstractions instead.IRequestHandler<T>
proxy that forward the call to a wrapped ICommandHandler<T>
.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.