使用 MediatR 和 Autofac 的组件注册问题
Component registration issue using MediatR and Autofac
我正在使用 Autofac 和 MediatR 构建基于 CQRS 的 .Net Core 2.1 应用程序。
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);
异常:
Unhandled Exception: System.InvalidOperationException: Error constructing handler for request of type MediatR.IRequestHandler2[Backend.MessageService.Commands.IdentifiedCommand
2[Backend.MessageService.Commands.CreateMessageCommand,System.Boolean],System.Boolean]. Register your handlers with the container. See the samples in GitHub for examples. ---> Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'MediatR.IRequestHandler2[[Backend.MessageService.Commands.IdentifiedCommand
2[[Backend.MessageService.Commands.CreateMessageCommand, Backend.MessageService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Backend.MessageService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
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> {...}
我可以知道缺少什么吗?
您发送给 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
请求。
添加这个解决了我的问题。
builder.RegisterType(typeof(IdentifiedCommandHandler<CreateMessageCommand, bool>))
.As<IRequestHandler<IdentifiedCommand<CreateMessageCommand, bool>, bool>>()
.AsImplementedInterfaces();
我正在使用 Autofac 和 MediatR 构建基于 CQRS 的 .Net Core 2.1 应用程序。
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);
异常:
Unhandled Exception: System.InvalidOperationException: Error constructing handler for request of type MediatR.IRequestHandler
2[Backend.MessageService.Commands.IdentifiedCommand
2[Backend.MessageService.Commands.CreateMessageCommand,System.Boolean],System.Boolean]. Register your handlers with the container. See the samples in GitHub for examples. ---> Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'MediatR.IRequestHandler2[[Backend.MessageService.Commands.IdentifiedCommand
2[[Backend.MessageService.Commands.CreateMessageCommand, Backend.MessageService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Backend.MessageService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
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> {...}
我可以知道缺少什么吗?
您发送给 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
请求。
添加这个解决了我的问题。
builder.RegisterType(typeof(IdentifiedCommandHandler<CreateMessageCommand, bool>))
.As<IRequestHandler<IdentifiedCommand<CreateMessageCommand, bool>, bool>>()
.AsImplementedInterfaces();