Как выполнить асинхронную проверку ModelState с помощью FluentValidation в веб-API с использованием .NET Core - PullRequest
0 голосов
/ 07 марта 2019

Этот вопрос является продолжением этого поста - Как выполнить асинхронную проверку ModelState с FluentValidation в Web API? .

Мне было интересно, есть ли у FluentValidation способ выполнить асинхронную ModelStateпроверка в .net core web api.У меня есть класс Valentator FluentValidation, который содержит асинхронные методы проверки, такие как «MustAsync», что означает, что в моем классе бизнес-служб я вызываю этот валидатор вручную, используя «ValidateAsync».Я также хочу использовать этот же класс валидатора для проверки модели, поступающей из запроса.Я просмотрел документы и прочитал, что единственный способ сделать это - вручную вызвать метод ValidateAsync (), поскольку конвейер .net является синхронным.Я бы предпочел не вызывать этот метод вручную из моего контроллера, я бы предпочел либо зарегистрировать его при запуске (чтобы инфраструктура автоматически вызывала валидатор в моей модели), либо украсить мою модель запроса валидатором.

Кто-нибудь смог достичь этого?

Спасибо!

1 Ответ

0 голосов
/ 25 марта 2019

Исходя из связанного вопроса, я немного адаптировал код для совместимости с ASP.NET Core (2.2, в моем случае).В общем, это использует интерфейс IAsyncActionFilter.Вы можете прочитать об этом в официальных документах .

public class ModelValidationActionFilter : IAsyncActionFilter
{
    private readonly IValidatorFactory _validatorFactory;
    public ModelValidationActionFilter(IValidatorFactory validatorFactory) => _validatorFactory = validatorFactory;

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var allErrors = new Dictionary<string, object>();

        // Short-circuit if there's nothing to validate
        if (context.ActionArguments.Count == 0)
        {
            await next();
            return;
        }

        foreach (var (key, value) in context.ActionArguments)
        {
            // skip null values
            if (value == null)
                continue;

            var validator = _validatorFactory.GetValidator(value.GetType());

            // skip objects with no validators
            if (validator == null)
                continue;

            // validate
            var result = await validator.ValidateAsync(value);

            // if it's valid, continue
            if (result.IsValid) continue;

            // if there are errors, copy to the response dictonary
            var dict = new Dictionary<string, string>();

            foreach (var e in result.Errors)
                dict[e.PropertyName] = e.ErrorMessage;

            allErrors.Add(key, dict);
        }

        if (allErrors.Any())
        {
            // Do anything you want here, if the validation failed.
            // For example, you can set context.Result to a new BadRequestResult()
            // or implement the Post-Request-Get pattern.
        }
        else
            await next();
    }
}

Если вы хотите применить этот фильтр глобально, вы можете добавить фильтр к вызову AddMvc в вашем Startupучебный класс.Например:

 services.AddMvc(options => 
{
    options.Filters.Add<ModelValidationActionFilter>();

    // uncomment the following line, if you want to disable the regular validation
    // options.ModelValidatorProviders.Clear();
});
...