Aller au contenu principal

Les formulaires

Notions théoriques

DataAnnotations pour la validation

Les DataAnnotations servent à la fois au mapping EF Core ET à la validation des formulaires. Quand un formulaire est soumis, ASP.NET Core valide automatiquement les données selon ces attributs :

using System.ComponentModel.DataAnnotations;

public class Article
{
[Required(ErrorMessage = "Le titre est obligatoire.")]
[StringLength(200, MinimumLength = 5,
ErrorMessage = "Le titre doit contenir entre 5 et 200 caractères.")]
[Display(Name = "Titre de l'article")]
public string Titre { get; set; } = string.Empty;

[Required(ErrorMessage = "Le contenu est obligatoire.")]
[MinLength(10, ErrorMessage = "Le contenu doit contenir au moins 10 caractères.")]
public string Contenu { get; set; } = string.Empty;

[EmailAddress(ErrorMessage = "L'adresse e-mail n'est pas valide.")]
public string? Email { get; set; }

[Range(0, 100, ErrorMessage = "La note doit être entre 0 et 100.")]
public int? Note { get; set; }

[Url(ErrorMessage = "L'URL n'est pas valide.")]
public string? SiteWeb { get; set; }

[RegularExpression(@"^\d{5}$", ErrorMessage = "Le code postal doit contenir 5 chiffres.")]
public string? CodePostal { get; set; }
}

Attributs de validation courants

AttributDescription
[Required]Champ obligatoire
[StringLength(max, MinimumLength=min)]Longueur entre min et max
[MaxLength(n)]Longueur maximale
[MinLength(n)]Longueur minimale
[Range(min, max)]Valeur numérique entre min et max
[EmailAddress]Format e-mail valide
[Url]Format URL valide
[RegularExpression(pattern)]Validation par expression régulière
[Compare("AutreChamp")]Deux champs doivent être identiques (ex: confirmation de mot de passe)

ModelState.IsValid dans le contrôleur

Avant de sauvegarder, vérifiez ModelState.IsValid :

[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Article article)
{
if (ModelState.IsValid)
{
// Toutes les validations ont réussi → sauvegarder
_context.Add(article);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
// Au moins une validation a échoué → réafficher le formulaire avec les erreurs
return View(article);
}

Afficher les erreurs dans la vue Razor

Les Tag Helpers de validation affichent automatiquement les messages d'erreur :

<form asp-action="Create" method="post">

<!-- Résumé de toutes les erreurs (optionnel) -->
<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<div class="mb-3">
<!-- Label généré depuis [Display(Name = "...")] -->
<label asp-for="Titre" class="form-label"></label>

<!-- Input avec classe is-invalid si erreur -->
<input asp-for="Titre" class="form-control" />

<!-- Message d'erreur spécifique à ce champ -->
<span asp-validation-for="Titre" class="text-danger"></span>
</div>

<div class="mb-3">
<label asp-for="Contenu" class="form-label"></label>
<textarea asp-for="Contenu" class="form-control" rows="8"></textarea>
<span asp-validation-for="Contenu" class="text-danger"></span>
</div>

<button type="submit" class="btn btn-primary">Publier</button>
</form>

Validation côté client (jQuery Validate)

ASP.NET Core inclut la validation côté client automatique. Il faut inclure les scripts dans la section Scripts de la vue :

@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Cette validation s'exécute dans le navigateur avant l'envoi du formulaire — l'utilisateur voit les erreurs immédiatement, sans rechargement de page.

La validation côté serveur est indispensable

La validation côté client améliore l'expérience utilisateur, mais elle peut être contournée (JavaScript désactivé, requêtes HTTP directes). La validation côté serveur (ModelState.IsValid) doit toujours être présente. Elle est la seule garantie de sécurité.

Comparaison avec Symfony et Spring Boot
// Symfony : contraintes sur l'entité (similaire)
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\NotBlank(message: "Le titre est obligatoire")]
#[Assert\Length(max: 200)]
private string $titre = '';
// Spring Boot / Bean Validation (similaire)
@NotBlank(message = "Le titre est obligatoire")
@Size(max = 200)
private String titre;

Dans les trois frameworks, le principe est identique : les contraintes sont déclarées sur l'entité et vérifiées automatiquement lors de la soumission du formulaire.

Exemple pratique

Formulaire de création d'article complet avec validation :

// Models/Article.cs — Entité avec validations
public class Article
{
public int Id { get; set; }

[Required(ErrorMessage = "Le titre est obligatoire.")]
[StringLength(200, MinimumLength = 5,
ErrorMessage = "Le titre doit contenir entre 5 et 200 caractères.")]
[Display(Name = "Titre de l'article")]
public string Titre { get; set; } = string.Empty;

[Required(ErrorMessage = "Le contenu est obligatoire.")]
[MinLength(10, ErrorMessage = "Contenu trop court (minimum 10 caractères).")]
[Display(Name = "Contenu")]
public string Contenu { get; set; } = string.Empty;

public DateTime DateCreation { get; set; } = DateTime.UtcNow;
public bool EstPublie { get; set; }
}
<!-- Views/Articles/Create.cshtml -->
@model MonBlog.Models.Article

@{ ViewData["Title"] = "Nouvel article"; }

<h1>Créer un article</h1>

<form asp-action="Create" method="post" class="needs-validation">
<div asp-validation-summary="ModelOnly" class="alert alert-danger d-none"></div>

<div class="mb-3">
<label asp-for="Titre" class="form-label"></label>
<input asp-for="Titre" class="form-control" placeholder="Titre de votre article..." />
<span asp-validation-for="Titre" class="text-danger small"></span>
</div>

<div class="mb-3">
<label asp-for="Contenu" class="form-label"></label>
<textarea asp-for="Contenu" class="form-control" rows="12"
placeholder="Rédigez votre article ici..."></textarea>
<span asp-validation-for="Contenu" class="text-danger small"></span>
</div>

<div class="mb-3 form-check">
<input asp-for="EstPublie" class="form-check-input" type="checkbox" />
<label asp-for="EstPublie" class="form-check-label">Publier immédiatement</label>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Publier</button>
<a asp-action="Index" class="btn btn-outline-secondary">Annuler</a>
</div>
</form>

@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Test de mémorisation/compréhension


Quel attribut force un champ à être renseigné (non vide) ?


Quel attribut définit une longueur minimale ET maximale pour une chaîne ?


Comment affiche-t-on le message d'erreur de validation pour le champ Titre dans une vue Razor ?


Quelle propriété du contrôleur indique si la validation a réussi ?


Quel attribut valide qu'une valeur numérique est comprise entre 0 et 100 ?


Pourquoi la validation côté serveur (ModelState.IsValid) est-elle indispensable même si la validation côté client est active ?


TP pour réfléchir et résoudre des problèmes

Vous allez améliorer la validation du formulaire de création d'articles de MonBlog.

Étape 1 — Ajouter des validations enrichies sur l'entité Article


Bonne pratique - ErrorMessage explicite

Fournissez toujours un ErrorMessage clair dans vos attributs de validation. Le message par défaut généré par ASP.NET Core est en anglais et peu convivial. Un message en français, avec la contrainte explicite ("entre 5 et 200 caractères"), aide l'utilisateur à corriger son saisie du premier coup.

Étape 2 — Afficher les erreurs dans le formulaire Create


Bonne pratique - Validation pour chaque champ

Ajoutez un <span asp-validation-for="..."> sous chaque champ de formulaire. Les utilisateurs voient ainsi immédiatement quel champ pose problème, sans avoir à chercher dans un résumé d'erreurs général.

Étape 3 — Activer la validation côté client


Bonne pratique - Validation côté client comme confort, pas comme sécurité

La validation côté client améliore l'expérience utilisateur en donnant un retour immédiat. Mais elle ne remplace pas ModelState.IsValid côté serveur. Implémentez toujours les deux : la validation client pour le confort, la validation serveur pour la sécurité.

📌 Une solution