Сценарий
Я пытаюсь настроить препроцессор команд в конвейере запросов CQRS с использованием поведения конвейера MediatR и Autofac для маршрутизации запросов. Моя цель состоит в том, чтобы препроцессор запускался только для команд (ICommand), а не для всех запросов (IRequest), что приведет к выполнению препроцессором команд, запросов и событий.Проблема
Я могу заставить свой GenericPreProcessor или любой другой препроцессор нормально работать для всех типов запросов, но любой метод, который я использовал, чтобы " filter» инъекция либо возвращает ошибку, либо просто не выполняет нужный препроцессор.
Моя конфигурация конвейера «работа для всех запросов» в 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]
Мобильная версия