MediatR беглый ответ проверки от поведения конвейера
У меня есть поведение MediatR Pipeline для проверки команд с помощью библиотеки FluentValidation. Я видел много примеров, когда вы вызываете исключение ValidationException из поведения, и это прекрасно работает для меня. Однако в моем сценарии я хочу обновить свой объект ответа с ошибками проверки.
Я могу построить и запустить следующий код. Когда я устанавливаю точку останова в операторе if, CommandResponse создается с ошибками проверки, как и ожидалось - но когда ответ получен исходным вызывающим, он становится нулевым:
public class RequestValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public RequestValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext(request);
// Run the associated validator against the request
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if(failures.Count != 0)
{
var commandResponse = new CommandResponse(failures) { isSuccess = false };
return commandResponse as Task<TResponse>;
}
else
{
return next();
}
}
}
Я думаю, что это связано с моей попыткой привести его к типу Task - но без этого я получаю ошибки компилятора. Я возвращаю тот же тип, что и мой обработчик команд, если проверка прошла успешно, поэтому я не понимаю, почему он возвращает нулевой экземпляр ожидаемого ответа. Я чувствую, что есть лучший способ справиться с этим, но я попробовал несколько вариантов безрезультатно. Какие-либо предложения? Есть ли лучший шаблон для использования? Я бы предпочел оставить это в процессе, так как оно будет многократно использоваться.
1 ответ
В итоге я добавил промежуточное программное обеспечение для обработки исключений в проект MVC. Вместо того, чтобы пытаться вернуть ошибки валидации в качестве объекта, я выкидываю исключительную ситуацию ValidationException в поведение конвейера, а промежуточное ПО обрабатывает все исключения во всем проекте. Это на самом деле сработало лучше, так как я обрабатываю все исключения в одном месте на более высоком уровне в цепочке обработки.
Вот обновленная часть кода, который я разместил:
if(failures.Count != 0)
{
// If any failures are found, throw a custom ValidationException object
throw new ValidationException(failures);
}
else
{
// If validation passed, allow the command or query to continue:
return next();
}
Вот промежуточное программное обеспечение для обработки исключений:
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context /* other dependencies */)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
// Log issues and handle exception response
if (exception.GetType() == typeof(ValidationException))
{
var code = HttpStatusCode.BadRequest;
var result = JsonConvert.SerializeObject(((ValidationException)exception).Failures);
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
else
{
var code = HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new { isSuccess = false, error = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
}
}
Затем вы регистрируете промежуточное программное обеспечение в вашем стартапе перед добавлением MVC:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMvc();
}
Примечание. Вы также можете создать метод расширения для своего промежуточного программного обеспечения:
public static class ErrorHandlingMiddlewareExtension
{
public static IApplicationBuilder UseErrorHandlingMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
Что позволяет вам зарегистрировать это так:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseErrorHandlingMiddleware();
app.UseMvc();
}
Я использую.Net core 3.1, и мне не удалось обнаружить исключения, когда я добавил промежуточное ПО перед следующим блоком в Configure
функция Startup
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
проверьте метод настройки. Обязательно зарегистрируйте его после указанного выше утверждения. Это довольно очевидно, но может помочь кому-то вроде меня.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ErrorHandlingMiddleware>();