namespace Webzine.WebApplication.Filters; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; /// /// Filtre d'action qui valide automatiquement le ModelState avant l'exécution du contrôleur. /// Mesure également le temps d'exécution de chaque action (niveau Trace). /// public class ValidationActionFilter : IActionFilter { private readonly ILogger logger; /// /// Initializes a new instance of the class. /// /// Service de journalisation injecté. public ValidationActionFilter(ILogger logger) { this.logger = logger; } /// public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { var erreurs = context.ModelState .Where(e => e.Value?.Errors.Count > 0) .Select(e => $"{e.Key}: {string.Join(", ", e.Value!.Errors.Select(err => err.ErrorMessage))}") .ToList(); this.logger.LogWarning( "Validation échouée pour {Action} : {Erreurs}", context.ActionDescriptor.DisplayName, string.Join(" | ", erreurs)); string actionName = context.RouteData.Values["action"]?.ToString() ?? string.Empty; // cas spécial: titre details if (actionName.Equals("Index", StringComparison.OrdinalIgnoreCase)) { context.Result = new RedirectResult("/"); return; } // Récupère le modèle soumis (premier argument de l'action, s'il existe) object? model = context.ActionArguments.Values.FirstOrDefault(); if (context.Controller is Controller controller) { context.Result = new ViewResult { ViewName = actionName, ViewData = new Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary( controller.ViewData) { Model = model, }, }; } else { context.Result = new BadRequestObjectResult(context.ModelState); } } } /// public void OnActionExecuted(ActionExecutedContext context) { } }