我能够让我的命令和查询与它们各自的处理程序一起正常工作,但装饰器却没有。
我正在将 Autofac 与 MediatR 一起使用。一个复杂的问题是我的消息(命令/查询/事件)在一个单独的项目中,因此需要通过 Autofac 的程序集进行注册。
这是我的 CommandHandler 接口:
public interface ICommandHandler<in TCommand, TResponse> : IRequestHandler<TCommand, TResponse>
where TCommand : MediatR.IRequest<TResponse>
{
}
一个示例 CommandHandler:
public class AddExternalLoginToUserCommandHandler : CommandHandler<AddExternalLoginToUser, CommonResult>
{
private readonly UserManager<AppUser> _userManager;
public AddExternalLoginToUserCommandHandler(
UserManager<AppUser> userManager, ILogger logger) : base(logger)
{
...
}
protected override async Task<CommonResult> HandleImplAsync(
AddExternalLoginToUser command, CancellationToken cancellationToken)
{
... details deleted...
return
new CommonResult(Outcome.Succeeded);
}
}
我的装饰器:
public class LoggingCommandDecorator<TCommand, TResult> : ICommandHandler<TCommand, TResult>
where TCommand : ICommand<TResult>
where TResult : ICommonResult
{
private readonly ICommandHandler<TCommand,TResult> _commandHandler;
public LoggingCommandDecorator(ICommandHandler<TCommand,TResult> commandHandler)
{
_commandHandler = commandHandler;
}
public async Task<TResult> Handle(TCommand command, CancellationToken cancellationToken)
{
Debug.WriteLine("***** HOLY $%1@ IT WORKED ******");
TResult result = await _commandHandler.Handle(command, cancellationToken);
return result;
}
}
还有我的部分配置:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Database, Authentication and Azure config stuff deleted for clarity...
// AUTOFAC DI/IOC CONFIGURATION
var builder = new ContainerBuilder();
// Copies existing dependencies from IServiceCollection
builder.Populate(services);
// Enables contravariant Resolve() for interfaces with single contravariant ("in") arg
builder
.RegisterSource(new ContravariantRegistrationSource());
// Mediator itself
builder
.RegisterType<Mediator>()
.As<IMediator>()
.InstancePerLifetimeScope();
// Request handlers
builder
.Register<SingleInstanceFactory>(ctx => {
var c = ctx.Resolve<IComponentContext>();
return t => { object o; return c.TryResolve(t, out o) ? o : null; };
})
.InstancePerLifetimeScope();
// Notification handlers
builder
.Register<MultiInstanceFactory>(ctx => {
var c = ctx.Resolve<IComponentContext>();
return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
})
.InstancePerLifetimeScope();
// Register query handlers
builder.RegisterAssemblyTypes(typeof(QueryHandler<,>).GetTypeInfo().Assembly).AsImplementedInterfaces(); // via assembly scan
// REGISTER COMMAND HANDLERS AS KEYED SERVICE
Assembly commandHandlerAssembly = typeof(CommandHandler<,>).Assembly;
builder.RegisterAssemblyTypes(commandHandlerAssembly)
.As(t => t.GetInterfaces()
.Where(i => i.IsClosedTypeOf(typeof(ICommandHandler<,>)))
.Select(i => new KeyedService("command-handler", i)))
.AsImplementedInterfaces();
// REGISTER DECORATOR
builder.RegisterGenericDecorator(
typeof(LoggingCommandDecorator<,>),
typeof(ICommandHandler<,>),
fromKey: "command-handler");
// Finalize
var container = builder.Build();
//Create the IServiceProvider based on the container.
return new AutofacServiceProvider(container);
}
关于让装饰器处理程序触发的任何想法?如前所述,命令和查询运行良好。
跟进:开放泛型和装配扫描
MediatR Git 页面上有讨论 Autofac、Open Generics 和 Assembly 扫描的困难:
https://github.com/jbogard/MediatR/issues/128
在进行程序集扫描时,Autofac 似乎不支持注册开放的泛型......
我知道这个问题,但在我看来这不是一个因素。我知道程序集扫描和注册是成功的,因为命令处理程序已正确注册。还是我忽略了什么?