MediatR беглый ответ проверки от поведения конвейера - PullRequest
0 голосов
/ 09 января 2019

У меня есть поведение MediatR Pipeline для проверки команд с помощью библиотеки FluentValidation. Я видел много примеров, когда вы вызываете исключение ValidationException из поведения, и это прекрасно работает для меня. Однако в моем сценарии я хочу обновить свой объект ответа с ошибками проверки.

Я могу собрать и запустить следующий код. Когда я устанавливаю точку останова в операторе if, CommandResponse создается с ошибками проверки, как и ожидалось, но когда ответ получен исходным вызывающим, он равен null:

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 Ответ

0 голосов
/ 11 января 2019

В итоге я добавил промежуточное программное обеспечение для обработки исключений в проект 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();
}
...