3

Je configure un projet web api pour utiliser FluentValidation en utilisant le webapi integration package pour FluentValidation. Ensuite, j'ai créé un validateur qui utilise CustomAsync(...) pour exécuter des requêtes sur la base de données.Comment effectuer une validation asynchrone ModelState avec FluentValidation dans l'API Web?

Le problème est que la validation semble être bloquée lors de l'attente de la tâche de base de données. J'ai fait une enquête, il semble que l'API MVC ModelState est synchrone, et il appelle une méthode synchrone Validate(...) qui appelle FluentValidation à appeler task.Result, provoquant l'interblocage.

Est-il correct de supposer que les appels asynchrones ne fonctionneront pas bien avec la validation intégrée de webapi?

Et si c'est le cas, quelle est l'alternative? WebApi ActionFilters semble prendre en charge le traitement asynchrone. Ai-je besoin de créer mon propre filtre pour gérer la validation manuellement ou y a-t-il déjà quelque chose à faire que je ne vois pas?

Répondre

2

Je fini par créer un filtre personnalisé et sautée validation intégrée entièrement:

public class WebApiValidationAttribute : ActionFilterAttribute 
{ 
    public WebApiValidationAttribute(IValidatorFactory factory) 
    { 
     _factory = factory; 
    } 

    IValidatorFactory _factory; 

    public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) 
    { 
     if (actionContext.ActionArguments.Count > 0) 
     { 
      var allErrors = new Dictionary<string, object>(); 

      foreach (var arg in actionContext.ActionArguments) 
      { 
       // skip null values 
       if (arg.Value == null) 
        continue; 

       var validator = _factory.GetValidator(arg.Value.GetType()); 

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

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

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

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

        allErrors.Add(arg.Key, dict); 
       } 
      } 

      // if any errors were found, set the response 
      if (allErrors.Count > 0) 
      { 
       actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, allErrors); 
       actionContext.Response.ReasonPhrase = "Validation Error"; 
      } 
     } 
    } 
}