Dans ASP.NET Core, le pipeline de traitement des requêtes peut être étendu à l'aide de filtres d'action pour gérer des préoccupations transversales telles que la journalisation, la gession des exceptions ou la validation des données. En interceptant le cycle de vie d'une action, il est possible d'exécuter du code avant ou après l'invocation du contrôleur.
Par défaut, l'infrastructure API valide automatiquement les modèles et renvoie une réponse 400 Bad Request si des erreurs sont détectées. Pour personnaliser ce comportement et renvoyer un format de réponse spécifique, il est nécessaire de désactiver ce filtre par défaut et d'implémenter une logique de validation sur mesure.
Configuration des servcies et désactivation du comportement par défaut
Lors de l'enregistrement des contrôleurs, le filtre de validation automatique doit être désactivé en définissant SuppressModelStateInvalidFilter sur true. Cela permet d'injecter un filtre global personnalisé.
public void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddControllers(config =>
{
config.Filters.Add<CustomModelValidationFilter>();
config.ModelBindingMessageProvider.SetMissingBindRequiredValueAccessor(
fieldName => $"Le champ '{fieldName}' est obligatoire.");
})
.ConfigureApiBehaviorOptions(apiOptions =>
{
apiOptions.SuppressModelStateInvalidFilter = true;
});
}
Implémentation du filtre de validation personnalisé
Une classe implémentant IActionFilter est créée pour évaluer l'état du modèle dans la méthode OnActionExecuting. Si des erreurs sont présentes, elles sont transformées en une structure de données personnalisée et le pipeline est court-circuité en définissant le résultat de l'action.
public class CustomModelValidationFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext executionContext)
{
if (!executionContext.ModelState.IsValid)
{
var validationErrors = executionContext.ModelState
.Where(entry => entry.Value.Errors.Any())
.Select(entry => new ValidationErrorDetail
{
PropertyName = entry.Key,
ErrorMessages = entry.Value.Errors.Select(e => e.ErrorMessage).ToList()
})
.ToList();
var apiResponse = new StandardApiResponse
{
StatusCode = 400,
Message = "Échec de la validation des données d'entrée.",
Errors = validationErrors
};
executionContext.Result = new BadRequestObjectResult(apiResponse);
}
}
public void OnActionExecuted(ActionExecutedContext executedContext)
{
}
}
public class ValidationErrorDetail
{
public string PropertyName { get; set; }
public List<string> ErrorMessages { get; set; }
}
public class StandardApiResponse
{
public int StatusCode { get; set; }
public string Message { get; set; }
public List<ValidationErrorDetail> Errors { get; set; }
}