Проблема регистрации компонентов с использованием MediatR и Autofac - PullRequest
0 голосов
/ 31 августа 2018

Я создаю приложение .Net Core 2.1 на основе CQRS, используя Autofac и MediatR.

public class MediatorModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();

        var mediatrOpenTypes = new[]
        {
            typeof(IRequestHandler<,>),
            typeof(INotificationHandler<>),
        };

        foreach (var mediatrOpenType in mediatrOpenTypes)
        {
            builder
                .RegisterAssemblyTypes(typeof(CreateMessageCommand.GetTypeInfo().Assembly)
                .AsClosedTypesOf(mediatrOpenType)
                .AsImplementedInterfaces();
        }

        builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
        builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));

        builder.Register<ServiceFactory>(ctx =>
        {
            var c = ctx.Resolve<IComponentContext>();
            return t => c.Resolve(t);
        });

    }
}

Когда я передаю команду посреднику, она отлично работает, и выполняется Handle () в обработчике команд.

var cmd = new CreateMessageCommand("Foo")
_mediator.Send(cmd)

Когда я выполняю это таким образом, дела идут не очень хорошо

var cmd = new CreateMessageCommand("Foo")
var req = new IdentifiedCommand<CreateMessageCommand, bool>(cmd, @event.Id);
await _mediator.Send(req);

Исключение:

Необработанное исключение: System.InvalidOperationException: Ошибка создания обработчика для запроса типа MediatR.IRequestHandler 2[Backend.MessageService.Commands.IdentifiedCommand 2 [Backend.MessageService.Commands.CreateMessageCommand, System.Boolean], System.Boolean]. Зарегистрируйте ваши обработчики в контейнере. Смотрите примеры в GitHub. ---> Autofac.Core.Registration.ComponentNotRegisteredException: запрошенная служба 'MediatR.IRequestHandler 2[[Backend.MessageService.Commands.IdentifiedCommand 2 [[Backend.MessageService.Commands.CreateMessageCommand, Backend.MessageService, Версия = 1.0.0.0, Culture = нейтральный, PublicKeyTey ], [System.Boolean, System.Private.CoreLib, версия = 4.0.0.0, культура = нейтральная, PublicKeyToken = 7cec85d7bea7798e]], Backend.MessageService, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = null], [система .Boolean, System.Private.CoreLib, версия = 4.0.0.0, культура = нейтральная, PublicKeyToken = 7cec85d7bea7798e]] 'не была зарегистрирована. Чтобы избежать этого исключения, либо зарегистрируйте компонент для предоставления услуги, проверьте регистрацию службы с помощью IsRegistered (), либо используйте метод ResolveOptional () для разрешения необязательной зависимости.

public class IdentifiedCommand<T, R> : IRequest<R>
    where T : IRequest<R>
{
    public T Command { get; }
    public Guid Id { get; }
    public IdentifiedCommand(T command, Guid id)
    {
        Command = command;
        Id = id;
    }
}

public class IdentifiedCommandHandler<T, R> :
    IRequestHandler<IdentifiedCommand<T, R>, R>
    where T : IRequest<R> {...}

Могу я узнать, чего не хватает?

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Добавление этой проблемы решило мою проблему.

builder.RegisterType(typeof(IdentifiedCommandHandler<CreateMessageCommand, bool>))
    .As<IRequestHandler<IdentifiedCommand<CreateMessageCommand, bool>, bool>>()
    .AsImplementedInterfaces();
0 голосов
/ 01 сентября 2018

Команда, которую вы отправляете в MediatR, имеет тип IdentifiedCommand<CreateMessageCommand, bool>. Поэтому MediatR будет искать обработчик типа IRequestHandler<IdentifiedCommand<CreateMessageCommand, bool>, bool>>.

Контейнер DI обычно делает это, сначала ищет точное соответствие, а затем рассматривает открытые регистрации универсальных типов. В этом случае он будет искать регистрацию IRequestHandler<,>, для которой он вставит аргументы типа IdentifiedCommand<CreateMessageCommand, bool> и bool. Однако ваш обработчик команд не реализует IRequestHandler<T, R>, вместо этого он реализует IRequestHandler<IdentifiedCommand<T, R>, R>, что не подходит для этого. Таким образом, контейнер DI не находит обработчик и выдаст эту ошибку.

Чтобы это работало, вам нужно будет реализовать тип так, как его будет искать контейнер DI. Так что вместо этого вам придется реализовать IRequestHandler<T, R>.

К сожалению, это также означает, что у вас не может быть безопасного типа для принятия IdentifiedCommand<T, R> в обработчике. Вместо этого вы просто получаете запрос T, с которым вам придется работать.

...