Сценарий
Я пытаюсь настроить препроцессор команд в конвейере запросов CQRS, используя поведение конвейера MediatR и Autofac для маршрутизации запросов. Моя цель состоит в том, чтобы препроцессор запускался только для команд (ICommand), а не для всех запросов (IRequest), что приведет к выполнению препроцессором команд, запросов и событий.
Проблема
Я могу заставить свой GenericPreProcessor или любой другой препроцессор нормально работать для всех типов запросов, но любой метод, который я использовал, чтобы попытаться «фильтровать» внедрение либо возвращает ошибку, либо просто не выполняет нужный препроцессор.
Моя конфигурация конвейера «работа для всех запросов» в Autofac выглядит следующим образом:
Код: Выделить всё
// Pipeline pre/post processors
builder
.RegisterGeneric(typeof(RequestPostProcessorBehavior))
.As(typeof(IPipelineBehavior));
builder
.RegisterGeneric(typeof(RequestPreProcessorBehavior))
.As(typeof(IPipelineBehavior));
// Works as desired: Fires generic pre-processor for ALL requests, both cmd and query
builder
.RegisterGeneric(typeof(GenericRequestPreProcessor))
.As(typeof(IRequestPreProcessor));
// Works for all requests, but I need a way to limit it to commands
builder
.RegisterGeneric(typeof(MyCommandPreProcessor))
.As(typeof(IRequestPreProcessor));
Код: Выделить всё
builder
.RegisterGeneric(typeof(MyCommandPreProcessor)) // Note generic
.As(typeof(IRequestPreProcessor));
// Intellisense error "Unexpected use of an unbound generic"
builder
.RegisterType(typeof(MyCommandPreProcessor)) // Note non-generic
.As(typeof(IRequestPreProcessor));
// Intellisense error "Unexpected use of an unbound generic"
builder
.RegisterType(typeof(MyCommandPreProcessor)) // Note non-generic
.As(typeof(IRequestPreProcessor));
// No errors, but MyCommandPreProcessor not firing
Код: Выделить всё
public class MyCommandPreProcessor : IRequestPreProcessor
{
public Task Process(TRequest request, CancellationToken cancellationToken)
{
Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
return Task.CompletedTask;
}
}
- OR -
public class MyCommandPreProcessor : IRequestPreProcessor
{
public Task Process(TRequest request, CancellationToken cancellationToken)
{
Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
return Task.CompletedTask;
}
}
Есть идеи о том, как зарегистрировать препроцессор, который будет работать только с типами IRequest, которые являются закрытыми типами ICommand?
Вспомогательные материалы
Проект на GitHub
Весь минимальный пример проекта можно просмотреть или клонирован по адресу https://github.com/jhoiby/MediatRPreProcessorTest
Autofac MediatR Config
Рабочая конфигурация с одним GenericRequestPreProcessor для всех запросов.
Код: Выделить всё
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
var mediatrOpenTypes = new[]
{
typeof(IRequestHandler),
typeof(IRequestHandler),
typeof(INotificationHandler)
};
foreach (var mediatrOpenType in mediatrOpenTypes)
{
// Register all command handler in the same assembly as WriteLogMessageCommandHandler
builder
.RegisterAssemblyTypes(typeof(MyCommandHandler).GetTypeInfo().Assembly)
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
// Register all QueryHandlers in the same assembly as GetExternalLoginQueryHandler
builder
.RegisterAssemblyTypes(typeof(MyQueryHandler).GetTypeInfo().Assembly)
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
// Pipeline pre/post processors
builder.RegisterGeneric(typeof(RequestPostProcessorBehavior)).As(typeof(IPipelineBehavior));
builder.RegisterGeneric(typeof(RequestPreProcessorBehavior)).As(typeof(IPipelineBehavior));
builder.RegisterGeneric(typeof(GenericRequestPreProcessor)).As(typeof(IRequestPreProcessor));
// builder.RegisterGeneric(typeof(GenericRequestPostProcessor)).As(typeof(IRequestPostProcessor));
// builder.RegisterGeneric(typeof(GenericPipelineBehavior)).As(typeof(IPipelineBehavior));
builder.Register(ctx =>
{
var c = ctx.Resolve();
return t => c.Resolve(t);
});
builder.Register(ctx =>
{
var c = ctx.Resolve();
return t => (IEnumerable)c.Resolve(typeof(IEnumerable).MakeGenericType(t));
});
Я экспериментирую с обоими из них, универсальными и неуниверсальными:
Код: Выделить всё
public class MyCommandPreProcessor : IRequestPreProcessor
{
public Task Process(TRequest request, CancellationToken cancellationToken)
{
Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
return Task.CompletedTask;
}
}
- AND -
public class MyCommandPreProcessor : IRequestPreProcessor
{
public Task Process(TRequest request, CancellationToken cancellationToken)
{
Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
return Task.CompletedTask;
}
}
Код: Выделить всё
// Requests
IMediatR.IRequest
Подробнее здесь: [url]https://stackoverflow.com/questions/48045989/executing-mediatr-preprocessor-only-for-specific-interface-types-commands[/url]
Мобильная версия