AddTransient, AddScoped, AddSingleton : différences en C# avec exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

AddTransient, AddScoped et AddSingleton : comment ne plus se perdre dans les cycles de vie des services C#

\n\n

Avez-vous déjà eu cette réflexion : « Pourquoi mon service conserve-t-il des données entre les requêtes alors que je ne lui ai rien demandé ? » Ou au contraire : « Pourquoi un nouvel objet est-il créé à chaque fois, et je perds l’état ? »

\n\n

Bienvenue dans l’univers de l’injection de dépendances (Dependency Injection, DI) dans ASP.NET Core ! C’est l’un des sujets les plus puissants et pourtant les plus déroutants pour les débutants. Aujourd’hui, nous allons décortiquer les trois piliers de la gestion des objets en C# : AddTransient, AddScoped et AddSingleton.

\n\n

À la fin de cet article, vous comprendrez non seulement la différence, mais vous pourrez aussi répondre avec assurance à cette question lors d’un entretien technique (oui, les recruteurs adorent la poser !). C’est parti !

\n\n

Qu’est-ce qu’un cycle de vie de service et pourquoi est-ce important ?

\n\n

Imaginez que votre application est un restaurant. Les services sont les cuisiniers, les serveurs et la vaisselle. Le cycle de vie détermine combien de temps ils « vivent » :

\n\n
    \n
  • Transient — un employé jetable. Il arrive, prépare une assiette de soupe et s’en va. Nouvelle commande = nouvel employé.
  • \n
  • Scoped — un employé pour un seul service. Il s’occupe de tous les clients tant que le restaurant est ouvert (tant que la requête HTTP dure).
  • \n
  • Singleton — le chef cuisinier, qui travaille toute la vie du restaurant. Un seul pour toute l’application.
  • \n
\n\n

En C#, cette logique est implémentée via le conteneur DI intégré. Regardons le code.

\n\n

1. AddTransient — une nouvelle instance à chaque fois

\n\n

Quand l’utiliser : Pour des services légers sans état (stateless), qui ne stockent pas de données entre les appels. Idéal pour les repositories, les helpers, les utilitaires.

\n\n

Comment ça fonctionne : Chaque fois que vous demandez le service (via le constructeur ou directement depuis le conteneur), un nouvel objet est créé.

\n\n
// Enregistrement dans Program.cs\nbuilder.Services.AddTransient<IMyService, MyService>();\n\n// Exemple de service\npublic interface IMyService\n{\n    Guid GetInstanceId();\n}\n\npublic class MyService : IMyService\n{\n    private readonly Guid _id = Guid.NewGuid();\n    public Guid GetInstanceId() => _id;\n}\n\n// Contrôleur qui utilise le service\npublic class HomeController : Controller\n{\n    private readonly IMyService _service1;\n    private readonly IMyService _service2;\n\n    public HomeController(IMyService service1, IMyService service2)\n    {\n        _service1 = service1;\n        _service2 = service2;\n    }\n\n    public IActionResult Index()\n    {\n        ViewBag.Id1 = _service1.GetInstanceId();\n        ViewBag.Id2 = _service2.GetInstanceId();\n        // Id1 et Id2 sont des GUID DIFFÉRENTS !\n        return View();\n    }\n}\n
\n\n

Important : Même au sein d’une seule requête HTTP, si vous injectez IMyService à deux endroits différents, vous obtiendrez deux objets distincts. Cela consomme plus de mémoire, mais élimine tout risque de « contamination » des données.

\n\n

2. AddScoped — une instance par requête

\n\n

Quand l’utiliser : Pour des services qui doivent être cohérents au sein d’une même requête HTTP. Par exemple, DbContext dans Entity Framework Core, les services de gestion de panier d’achat, les loggers de requêtes.

\n\n

Comment ça fonctionne : Dans une même requête HTTP (ou scope), une seule instance est créée. Si vous la demandez plusieurs fois, vous obtenez le même objet. Mais chaque nouvelle requête d’un autre utilisateur reçoit sa propre instance.

\n\n
// Enregistrement\nbuilder.Services.AddScoped<IScopedService, ScopedService>();\n\npublic interface IScopedService\n{\n    Guid GetInstanceId();\n}\n\npublic class ScopedService : IScopedService\n{\n    private readonly Guid _id = Guid.NewGuid();\n    public Guid GetInstanceId() => _id;\n}\n\n// Dans le même contrôleur\npublic                

Blogs

Book Recommendations