Enregistrer des données
Notions théoriques
Injection du DbContext dans le contrôleur
ASP.NET Core utilise l'injection de dépendances (IoC) : au lieu de créer manuellement le DbContext, on le demande via le constructeur du contrôleur. ASP.NET Core l'injecte automatiquement :
public class ArticlesController : Controller
{
private readonly MonBlogContext _context;
// Injection automatique du DbContext par ASP.NET Core
public ArticlesController(MonBlogContext context)
{
_context = context;
}
}
// Symfony : injection via le constructeur ou EntityManagerInterface
public function __construct(private EntityManagerInterface $em) {}
// Spring Boot : injection via @Autowired ou constructeur
@Autowired ArticleRepository articleRepository;
// ASP.NET Core : injection via constructeur (pas d'annotation nécessaire)
public ArticlesController(MonBlogContext context) { _context = context; }
Enregistrer un objet en base de données
Pour sauvegarder un nouvel article, trois étapes :
// 1. Ajouter l'objet au DbContext
_context.Articles.Add(article);
// 2. Persister en base de données (g énère et exécute INSERT INTO)
await _context.SaveChangesAsync();
// Doctrine (Symfony)
$em->persist($article); // 1. Marquer pour persistance
$em->flush(); // 2. Exécuter les requêtes SQL
// JPA Spring Boot
articleRepository.save(article); // Une seule ligne = persist + flush
// EF Core : Add + SaveChangesAsync
_context.Articles.Add(article);
await _context.SaveChangesAsync();
EF Core combine les deux étapes de Doctrine en une seule : SaveChangesAsync() gère à la fois le marquage et l'exécution.
async/await obligatoire
Les opérations de base de données sont asynchrones en ASP.NET Core. La règle : toujours utiliser les versions Async des méthodes EF Core et attendre leur résultat avec await :
// Syntaxe async/await
public async Task<IActionResult> Create(Article article)
{
_context.Articles.Add(article);
await _context.SaveChangesAsync(); // Attend la fin de l'opération
return RedirectToAction("Index");
}
En Java (JPA/Hibernate), les opérations de BDD sont synchrones par défaut. En C# ASP.NET Core, toutes les opérations I/O (base de données, fichiers, HTTP) doivent être asynchrones. Si vous oubliez await, le code compilera mais le comportement sera incorrect (la sauvegarde peut ne pas être terminée avant la redirection).
Actions GET et POST pour la création
Un formulaire de création nécessite deux actions dans le contrôleur :
// GET /Articles/Create — Affiche le formulaire vide
public IActionResult Create()
{
return View();
}
// POST /Articles/Create — Traite les données du formulaire
[HttpPost]
[ValidateAntiForgeryToken] // Protection contre les attaques CSRF
public async Task<IActionResult> Create(Article article)
{
if (ModelState.IsValid)
{
article.DateCreation = DateTime.UtcNow;
_context.Articles.Add(article);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(article); // Réaffiche le formulaire avec les erreurs
}
[ValidateAntiForgeryToken]
Cet attribut protège contre les attaques CSRF (Cross-Site Request Forgery). Il vérifie qu'un jeton caché dans le formulaire correspond à celui attendu par le serveur. La vue doit inclure <form asp-action="Create"> (qui génère automatiquement ce jeton).
Sans cet attribut, un site malveillant pourrait soumettre des formulaires à votre place. C'est une faille de sécurité critique. Toujours ajouter [ValidateAntiForgeryToken] sur les actions POST.
Exemple pratique
Contrôleur complet avec GET + POST pour créer un article :
// Controllers/ArticlesController.cs
using Microsoft.AspNetCore.Mvc;
using MonBlog.Data;
using MonBlog.Models;
public class ArticlesController : Controller
{
private readonly MonBlogContext _context;
public ArticlesController(MonBlogContext context)
{
_context = context;
}
// GET /Articles
public async Task<IActionResult> Index()
{
var articles = await _context.Articles.ToListAsync();
return View(articles);
}
// GET /Articles/Create
public IActionResult Create()
{
return View();
}
// POST /Articles/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
[Bind("Titre,Contenu,EstPublie")] Article article)
{
if (ModelState.IsValid)
{
article.DateCreation = DateTime.UtcNow;
_context.Articles.Add(article);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(article);
}
}
[Bind("Titre,Contenu,EstPublie")] limite les propriétés qui peuvent être affectées depuis le formulaire. Cela protège contre l'over-posting : un utilisateur malveillant qui enverrait des champs non attendus (par exemple, Id ou EstAdmin) pour modifier des données sensibles.
Vue Views/Articles/Create.cshtml correspondante :
@model MonBlog.Models.Article
@{
ViewData["Title"] = "Nouvel article";
}
<h1>Créer un article</h1>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="Titre"></label>
<input asp-for="Titre" class="form-control" />
<span asp-validation-for="Titre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Contenu"></label>
<textarea asp-for="Contenu" class="form-control" rows="10"></textarea>
<span asp-validation-for="Contenu" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Publier</button>
<a asp-action="Index" class="btn btn-secondary">Annuler</a>
</form>
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez implémenter l'action Create (GET + POST) pour créer des articles dans MonBlog.
Étape 1 — Injecter le DbContext dans ArticlesController
Déclarez le champ _context avec le mot-clé readonly. Cela garantit qu'il ne peut être assigné que dans le constructeur, évitant toute modification accidentelle dans les actions du contrôleur.
Étape 2 — Implémenter l'action POST Create
Avant d'enregistrer, vérifiez ModelState.IsValid. Cela garantit que toutes les DataAnnotations (Required, MaxLength...) ont été respectées. Si la validation échoue, réaffichez le formulaire avec return View(article) — les messages d'erreur s'afficheront automatiquement grâce aux Tag Helpers asp-validation-for.
Étape 3 — Rediriger après la création
Après un POST réussi, toujours rediriger vers une action GET avec RedirectToAction(). Ce patron (Post-Redirect-Get) évite que l'utilisateur re-soumette le formulaire en actualisant la page, ce qui créerait des doublons en base de données.