如何使用.NET Core在Web API中使用FluentValidation执行异步ModelState验证

时间:2019-03-07 15:59:46

标签: asp.net-core asp.net-core-webapi fluentvalidation

此问题是此帖子的后续操作-How to perform async ModelState validation with FluentValidation in Web API?

我想知道FluentValidation是否可以在.net核心Web API中执行异步ModelState验证。我有一个FluentValidation Validator类,其中包含异步验证方法,例如“ MustAsync”,这意味着在我的业务服务类中,我使用“ ValidateAsync”手动调用了验证器。我也想使用相同的验证器类来验证来自请求的模型。我仔细阅读了文档,了解到唯一的方法是手动调用“ ValidateAsync()”方法,因为.net管道是同步的。我宁愿不必从控制器内部手动调用此方法,我宁愿在启动时注册它(让框架自动在模型上调用验证器),也可以用验证器修饰请求模型。

有人能做到吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

基于链接的问题,我对代码进行了一些改动,以使其与ASP.NET Core(以我的情况为2.2)兼容。通常,这是使用IAsyncActionFilter接口。您可以in the official docs来了解它。

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();
});

答案 1 :(得分:0)

根据@nachtjasmin 上面的回答,您可以通过两种方式添加,

  1. 使用 AddMvc

    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<FluentValidationActionFilter>();
    });
    
  2. 使用 AddControllersWithViews

    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<FluentValidationActionFilter>();
    });
    

如果您的只是一个 Web API 并且您没有涉及任何 Razor 页面,那么您可以考虑使用 AddControllersWithViews 而不是 AddMvc,因为 AddMvc 使用 {{1 }} 在内部添加 AddControllersWithViews

您可以看到此信息 here for AddMvchere for AddControllersWithViews