Aller au contenu principal

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;
}
}
Comparaison avec Symfony et Spring Boot
// 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();
Comparaison avec Doctrine et JPA
// 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");
}
Différence avec Java

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).

Ne jamais omettre ValidateAntiForgeryToken

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);
}
}
L'attribut [Bind]

[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


Quelle méthode EF Core ajoute un objet à la file d'attente de persistance ?


Quelle méthode EF Core exécute réellement les requêtes SQL INSERT/UPDATE/DELETE ?


Quel attribut protège une action POST contre les attaques CSRF ?


Comment injecte-t-on le DbContext dans un contrôleur ASP.NET Core ?


Quel attribut limite les propriétés pouvant être affectées depuis un formulaire (protection over-posting) ?


Pourquoi les méthodes EF Core utilisent-elles async/await en ASP.NET Core ?


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


Bonne pratique - readonly pour les dépendances injectées

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


Bonne pratique - Toujours vérifier ModelState.IsValid

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


Bonne pratique - Post-Redirect-Get (PRG)

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.

📌 Une solution