Невозможно зарегистрировать IRequestPreProcessors в Mediatr
Я хочу зарегистрировать следующий фиктивный IRequestPreProcessor (Mediator 3)
public class IdentifyUserTypeCommandHandler : IRequestPreProcessor<RegisterUserCommand>
{
private readonly IOptions<TecApiOptions> _options;
public IdentifyUserTypeCommandHandler(IOptions<TecApiOptions> options)
{
_options = options;
}
public async Task Process(RegisterUserCommand request)
{
request.Type = "internal";
await Task.FromResult(true);
}
}
Для этого у меня есть настройки контейнера для сопоставления IRequestPreProcessor с моей конкретной реализацией IdentifyUserTypeCommandHandler
// Pipeline engine used internally to simplify controllers
services.AddMediatR();
// Pre-processors
services.AddTransient(typeof(IRequestPreProcessor<RegisterUserCommand>), typeof(IdentifyUserTypeCommandHandler));
// Registers command validator
services.AddTransient(typeof(IValidator<RegisterUserCommand>), typeof(RegisterUserCommandValidator));
// Registers generic behaviors
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(Pipeline<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
Как только я запускаю код, я получаю следующее исключение
System.ArgumentException: для открытия универсального типа службы "MediatR.Pipeline.IRequestPreProcessor`1[TRequest]" требуется зарегистрировать открытый универсальный тип реализации.
Я хочу запустить этот препроцессор только для команд типа RegisterUserCommand. Любая идея о том, как я могу решить эту проблему?
К вашему сведению,
public class LoggingBehavior<TCommand, TResponse> : IPipelineBehavior<TCommand, TResponse>
{
private readonly ILogger _logger;
public LoggingBehavior(ILoggerFactory loggerFactory)
{
_logger = loggerFactory?.CreateLogger(typeof(TCommand).Name) ?? throw new ArgumentNullException(nameof(loggerFactory));
}
public async Task<TResponse> Handle(TCommand request, RequestHandlerDelegate<TResponse> next)
{
try
{
_logger.LogInformation(LoggingEvents.RUN_HANDLER, $"Handling '{typeof(TCommand).Name}'");
var response = await next();
_logger.LogInformation(LoggingEvents.RUN_HANDLER, $"Handled '{typeof(TResponse).Name}'");
return response;
}
catch (Exception e)
{
_logger.LogError(
LoggingEvents.RUN_HANDLER_EXCEPTION, e,
$"An error occured while processing pipeline '{GetType().Name}' [{typeof(TCommand).Name} >> {typeof(TResponse).Name}]");
throw;
}
}
}
Спасибо, С уважением, Себ
3 ответа
Итак, после разговора с создателем библиотеки, похоже, что процессоры Pre и Post должны иметь общее определение.
public class GenericRequestPostProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse>
ИЛИ ЖЕ
public class GenericRequestPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
src: примеры
<TRequest>
а также <TRequest, TResponse>
необходимы при создании новых Pre/Post процессоров. Теперь на вопрос в 1 000 000 долларов я постараюсь ответить позже:
Как мы специализируем процессоры, чтобы они обрабатывали определенный набор запросов / команд (без необходимости проверять тип запроса)...
Если вы используете services.AddMediatR()
Убедитесь, что вы зарегистрировали встроенное поведение: RequestPreProcessorBehavior
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
services.AddMediatR();
Тогда ваш препроцессор должен иметь общее определение в соответствии с ответом @Sebastien:
public class PingDecorator<TRequest> : IRequestPreProcessor<TRequest>
{
public Task Process(TRequest request)
{
return Unit.Task;
}
}
Если вы хотите, чтобы ваш препроцессор использовался только с конкретным запросом:
public class PingDecorator<TRequest> : IRequestPreProcessor<TRequest> where TRequest:Ping
{
public Task Process(TRequest request)
{
request.Message = request.Message + " Decorated";
return Unit.Task;
}
}
В последней версии есть встроенная регистрация с использованием извлечения из сборки, регистрация не требуется. Обратите внимание, что я тестировал его с несколькими реализациями IRequestPreProcessor, и все они работают в том же порядке, в котором были написаны в коде. Я думаю, что это может быть семантическая ошибка, поскольку по логике не должно быть только одного RequestPreProcessor.