vendredi 28 février 2025

Dépendance Injection

 La Dépendance Injection (DI) dans C# .NET est un concept clé dans la gestion des dépendances des objets, et elle est souvent utilisée pour améliorer la testabilité, la flexibilité et la maintenabilité du code. Dans .NET Core et .NET 5+, la DI est supportée nativement par le framework, et tu peux l'utiliser pour injecter des services dans des classes via les constructeurs, les propriétés ou les méthodes.

🔹 1. Concept de base de la Dependency Injection (DI)

Le principe de la DI est simple : au lieu de créer des instances d'objets directement dans une classe (ce qui rend la classe dépendante de ces objets), l'instance de l'objet est injectée dans la classe par un container de DI. Cela permet de réduire les dépendances fortes et de rendre le code plus testable et modulaire.

Exemple simple de DI dans C# :

Voici un exemple simple où on injecte une dépendance (un service) dans une classe via le constructeur.


🔹 2. Injection par constructeur

Exemple :

// Interface représentant le service
public interface INotificationService
{
    void SendNotification(string message);
}

// Implémentation concrète du service
public class EmailNotificationService : INotificationService
{
    public void SendNotification(string message)
    {
        Console.WriteLine($"Email envoyé : {message}");
    }
}

// Classe cliente utilisant le service
public class UserController
{
    private readonly INotificationService _notificationService;

    // Injection de la dépendance par le constructeur
    public UserController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }

    public void RegisterUser(string username)
    {
        // Logique d'inscription (omise)
        _notificationService.SendNotification($"Utilisateur {username} inscrit avec succès.");
    }
}

🔹 3. Configurer la DI dans Program.cs (ou Startup.cs pour ASP.NET Core)

Dans une application ASP.NET Core, la DI est automatiquement configurée, mais dans d'autres types d'applications (comme une application console), tu dois configurer le container DI manuellement.

Exemple pour une application Console :

using Microsoft.Extensions.DependencyInjection;

class Program
{
    static void Main(string[] args)
    {
        // Configuration du container DI
        var serviceProvider = new ServiceCollection()
            .AddSingleton<INotificationService, EmailNotificationService>() // Ajouter EmailNotificationService à INotificationService
            .AddTransient<UserController>() // Ajouter UserController qui dépend de INotificationService
            .BuildServiceProvider();

        // Résolution et exécution
        var userController = serviceProvider.GetService<UserController>();
        userController.RegisterUser("Alice");
    }
}

Dans ce cas, EmailNotificationService est enregistré en tant que singleton (une seule instance pour toute l'application), et UserController est enregistré en tant que transient (une nouvelle instance à chaque fois qu'on en a besoin).


🔹 4. Types de durée de vie dans la DI

Tu peux spécifier la durée de vie des services que tu enregistres dans le container DI. Il existe trois types principaux :

  1. Singleton : Une seule instance du service sera utilisée pendant toute la durée de vie de l'application.

    services.AddSingleton<IMyService, MyService>();
    
  2. Transient : Une nouvelle instance du service est créée chaque fois qu'il est demandé.

    services.AddTransient<IMyService, MyService>();
    
  3. Scoped : Une instance est créée une seule fois par requête (utile surtout dans des applications web).

    services.AddScoped<IMyService, MyService>();
    

🔹 5. DI dans ASP.NET Core

Dans les applications ASP.NET Core, la DI est généralement configurée dans la méthode ConfigureServices du fichier Startup.cs (ou Program.cs dans .NET 6+).

Exemple de configuration dans ASP.NET Core (Program.cs) :

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                // Ajouter les services à DI
                services.AddSingleton<INotificationService, EmailNotificationService>();
                services.AddScoped<UserController>();

                // Ajouter les services requis pour l'application web
                services.AddControllersWithViews();
            });
}

Ensuite, tu peux utiliser l'injection de dépendance dans tes contrôleurs ASP.NET Core.

Exemple de contrôleur utilisant DI :

public class UserController : Controller
{
    private readonly INotificationService _notificationService;

    // Injection par constructeur
    public UserController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }

    public IActionResult Register(string username)
    {
        _notificationService.SendNotification($"Utilisateur {username} inscrit.");
        return View();
    }
}

🔹 6. Testabilité avec DI

L'un des grands avantages de l'utilisation de la DI est qu'elle permet de rendre le code plus testable. Par exemple, tu peux facilement mock ou simuler les dépendances dans tes tests unitaires.

Exemple avec Moq (mocker un service dans un test) :

using Moq;
using Xunit;

public class UserControllerTests
{
    [Fact]
    public void RegisterUser_ShouldSendNotification()
    {
        // Arrange
        var mockService = new Mock<INotificationService>();
        var controller = new UserController(mockService.Object);

        // Act
        controller.RegisterUser("Alice");

        // Assert
        mockService.Verify(service => service.SendNotification(It.IsAny<string>()), Times.Once);
    }
}

Dans cet exemple, la méthode SendNotification du service INotificationService est simulée avec Moq, et on vérifie qu'elle a été appelée une fois lorsque l'on appelle RegisterUser.


🧠 Conclusion

La Dépendance Injection dans C# .NET est essentielle pour structurer des applications modifiables et testables. Elle permet de séparer la logique d'injection de dépendances de l'implémentation réelle des classes, ce qui rend le code plus flexible et plus facile à maintenir.

  • Injections par constructeur : La méthode la plus courante.

  • Durée de vie des services : Singleton, Scoped et Transient.

  • Testabilité : DI rend les tests unitaires plus simples grâce à la simulation (mocking).



==================================

trois types principaux d'injection de dépendances 

🔷 1. Injection par constructeur (Constructor Injection)

C’est le type le plus courant et recommandé. La dépendance est injectée via le constructeur de la classe.

✅ Exemple :

public interface ILogger
{
    void Log(string message);
}

public class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine(message);
}

public class Service
{
    private readonly ILogger _logger;

    public Service(ILogger logger)  // injection ici
    {
        _logger = logger;
    }

    public void DoWork()
    {
        _logger.Log("Travail effectué");
    }
}

🔷 2. Injection par propriété (Property Injection)

La dépendance est injectée via une propriété publique. C’est utile quand la dépendance est optionnelle.

✅ Exemple :

public class Service
{
    public ILogger Logger { get; set; }  // injection par propriété

    public void DoWork()
    {
        Logger?.Log("Travail effectué");
    }
}

🔷 3. Injection par méthode (Method Injection)

La dépendance est transmise via une méthode. C’est utile quand la dépendance est temporaire ou nécessaire uniquement dans un contexte particulier.

✅ Exemple :

public class Service
{
    public void DoWork(ILogger logger)  // injection par méthode
    {
        logger.Log("Travail effectué");
    }
}

🧠 Comparatif rapide

Type Quand l’utiliser Avantages
Constructeur Dépendance obligatoire Clarté, immutabilité, testabilité
Propriété Dépendance facultative Plus flexible
Méthode Dépendance contextuelle ou temporaire Injection ciblée, pas de stockage

✅ Bonus : Frameworks de DI en C#

En .NET, l’injection de dépendance est prise en charge nativement via :

  • Microsoft.Extensions.DependencyInjection

  • Et d'autres comme Autofac, Ninject, Unity...


Aucun commentaire:

Enregistrer un commentaire

Dépendance Injection Lượt xem: