Autofa c generi c декоратор не запущен (с mediatr) - PullRequest
0 голосов
/ 06 августа 2020

У меня проблемы с декоратором generi c, и я не могу найти решение ни на одном из просмотренных мной топи c. Думаю, я близок, но что-то упускаю.

Для упрощения у меня есть API в .NetCore и модуль в. Net Standard. Я хочу управлять DI для модуля в. Net Standard, а API просто вызывает его в Startup.

В Program.cs я использую autofa c service provider factory

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

Команда / обработчик команд наследуется от 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;
    }
}

Декоратор

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

Думаю, я что-то пропустил с autofa c.

Заранее спасибо.

1 Ответ

0 голосов
/ 06 августа 2020

MediatR использует абстракцию IRequestHandler. Это означает, что реализация IMediator внутренне запрашивает спецификатор c IRequestHandler<T> из контейнера.

Вы, с другой стороны, получили ICommandHandler<T> из этого IRequestHandler<T> и реализовали декораторы более того. Однако Autofa c (и большинство контейнеров DI в этом отношении) не сможет обернуть запрошенный IRequestHandler<T> в декоратор для другого интерфейса. Это связано со способом настройки Autofa c.

Для решения вашей проблемы есть несколько решений:

  1. Удалите пользовательскую абстракцию ICommandHandler<T>. Кажется, это бесполезно и только усложняет ваше приложение.
  2. Замените реализацию по умолчанию IMediator на ту, которая разрешает ICommandHandler<T> абстракции.
  3. Создайте (generi c) IRequestHandler<T> прокси, который перенаправляет вызов на завернутый ICommandHandler<T>.
  4. Полностью отказаться от MediatR.
...