Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans ce guide de démarrage rapide, vous créez une application console .NET qui crée manuellement un ServiceCollection et un ServiceProvider correspondant. Vous découvrez comment inscrire des services et les résoudre à l’aide de l’injection de dépendances (DI). Cet article utilise le package NuGet Microsoft.Extensions.DependencyInjection pour illustrer les principes de base de l'injection de dépendances dans .NET.
Note
Cet article ne tire pas parti des fonctionnalités de l’hôte générique . Pour obtenir un guide plus complet, consultez Utiliser l’injection de dépendances dans .NET.
Get started
Pour commencer, créez une application console .NET nommée DI.Basics. Certaines des approches les plus courantes pour la création d’un projet de console sont référencées dans la liste suivante :
- Visual Studio : Menu Fichier > Nouveau > Projet .
- Visual Studio Code et l’extension du Kit de développement C# : option de menu Explorateur de solutions .
-
CLI .NET :
dotnet new consolecommande dans le terminal.
Vous devez ajouter la référence de package à Microsoft.Extensions.DependencyInjection dans le fichier projet. Quelle que soit l’approche, vérifiez que le projet ressemble au code XML suivant du fichier DI.Basics.csproj :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
</ItemGroup>
</Project>
Bases de l’injection de dépendances
L’injection de dépendances est un modèle de conception qui vous permet de supprimer les dépendances codées en dur et de rendre votre application plus gérable et testable. DI est une technique permettant d’atteindre l’inversion du contrôle (IoC) entre les classes et leurs dépendances.
Les abstractions pour di dans .NET sont définies dans le package NuGet Microsoft.Extensions.DependencyInjection.Abstractions :
- IServiceCollection: définit un contrat pour une collection de descripteurs de service.
- IServiceProvider: définit un mécanisme de récupération d’un objet de service.
- ServiceDescriptor: décrit un service avec son type de service, son implémentation et sa durée de vie.
Dans .NET, DI est géré en ajoutant des services et en les configurant dans un IServiceCollection. Une fois les services inscrits, une IServiceProvider instance est générée en appelant la BuildServiceProvider méthode. Le IServiceProvider agit en tant que conteneur pour tous les services inscrits, et il est utilisé pour la résolution des services.
Créer des exemples de services
Tous les services ne sont pas créés de façon égale. Certains services nécessitent une nouvelle instance chaque fois que le conteneur de services les obtient (transitoire), tandis que d’autres doivent être partagés entre les requêtes (scopé) ou pendant toute la durée de vie de l’application (singleton). Pour plus d’informations sur les durées de vie des services, consultez Durées de vie des services.
De même, certains services n’exposent qu’un type concret, tandis que d’autres sont exprimés sous la forme d’un contrat entre une interface et un type d’implémentation. Vous créez plusieurs variantes de services pour vous aider à illustrer ces concepts.
Créez un fichier C# nommé IConsole.cs et ajoutez le code suivant :
public interface IConsole
{
void WriteLine(string message);
}
Ce fichier définit une IConsole interface qui expose une méthode unique. WriteLine Ensuite, créez un fichier C# nommé DefaultConsole.cs et ajoutez le code suivant :
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
Le code précédent représente l’implémentation par défaut de l’interface IConsole . La méthode WriteLine écrit conditionnellement sur la console en fonction de la propriété IsEnabled.
Conseil / Astuce
Le nommage d’une implémentation est un choix que votre équipe de développement doit accepter. Le Default préfixe est une convention commune pour indiquer une implémentation par défaut d’une interface, mais elle n’est pas obligatoire.
Ensuite, créez un fichier IGreetingService.cs et ajoutez le code C# suivant :
public interface IGreetingService
{
string Greet(string name);
}
Ajoutez ensuite un nouveau fichier C# nommé DefaultGreetingService.cs et ajoutez le code suivant :
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
Le code précédent représente l’implémentation par défaut de l’interface IGreetingService . L’implémentation du service nécessite un IConsole paramètre de constructeur principal. La méthode Greet :
- Crée un
greetingélément donné .name - Appelle la
WriteLineméthode sur l’instanceIConsole. - Retourne
greetingà l’appelant.
Le dernier service à créer est le fichier FarewellService.cs , ajoutez le code C# suivant avant de continuer :
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
Représente FarewellService un type concret, et non une interface. Il doit être déclaré comme public pour le rendre accessible aux consommateurs. Contrairement à d’autres types d’implémentation de service déclarés comme internal et sealed, ce code montre que tous les services n’ont pas besoin d’être des interfaces. Il est également montré que les implémentations de service peuvent être sealed pour empêcher l’héritage et internal pour restreindre l’accès à l’assemblage.
Mettre à jour la Program classe
Ouvrez le fichier Program.cs et remplacez le code existant par le code C# suivant :
using Microsoft.Extensions.DependencyInjection;
// 1. Create the service collection.
var services = new ServiceCollection();
// 2. Register (add and configure) the services.
services.AddSingleton<IConsole>(
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
});
services.AddSingleton<IGreetingService, DefaultGreetingService>();
services.AddSingleton<FarewellService>();
// 3. Build the service provider from the service collection.
var serviceProvider = services.BuildServiceProvider();
// 4. Resolve the services that you need.
var greetingService = serviceProvider.GetRequiredService<IGreetingService>();
var farewellService = serviceProvider.GetRequiredService<FarewellService>();
// 5. Use the services
var greeting = greetingService.Greet("David");
var farewell = farewellService.SayGoodbye("David");
Le code mis à jour précédent illustre la procédure suivante :
- Créez une
ServiceCollectioninstance. - Inscrivez et configurez les services dans le
ServiceCollection.- En utilisant la surcharge de fabrique d’implémentation
IConsole, un typeDefaultConsoleest retourné avec sa valeurIsEnableddéfinie àtrue. - Le
IGreetingServiceest ajouté avec un type d’implémentation correspondant de typeDefaultGreetingService. -
FarewellServiceest ajouté en tant que type concret.
- En utilisant la surcharge de fabrique d’implémentation
- Générez l’élément
ServiceProviderà partir duServiceCollection. - Résolvez les services
IGreetingServiceetFarewellService. - Utilisez les services résolus pour saluer et dire au revoir à une personne nommée
David.
Si vous mettez à jour la propriété IsEnabled de DefaultConsole à false, les méthodes Greet et SayGoodbye omettent d'écrire les messages résultants dans la console. Un changement comme celui-ci permet de démontrer que le IConsole service est injecté dans les IGreetingService services et FarewellService qu’il s’agit d’une dépendance qui influence ce comportement des applications.
Tous ces services sont enregistrés en tant que singletons, bien que pour cet exemple, il fonctionne de façon identique s’ils avaient été enregistrés en tant que services transitoires ou à portée limitée.
Important
Dans cet exemple contrif, les durées de vie du service n’ont pas d’importance, mais dans une application réelle, vous devez examiner attentivement la durée de vie de chaque service.
Exécuter l’exemple d’application
Pour exécuter l’exemple d’application, appuyez sur F5 dans Visual Studio ou Visual Studio Code, ou exécutez la dotnet run commande dans le terminal. Une fois l’application terminée, la sortie suivante doit s’afficher :
Hello, David!
Goodbye, David!
Descripteurs de service
Les API les plus souvent utilisées pour ajouter des services au ServiceCollection sont des méthodes d'extension génériques nommées selon leur durée de vie, telles que :
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
Ces méthodes sont des méthodes pratiques qui créent une ServiceDescriptor instance et l’ajoutent au ServiceCollection. Il ServiceDescriptor s’agit d’une classe simple qui décrit un service avec son type de service, son type d’implémentation et sa durée de vie. Il peut également décrire les fabriques d’implémentation et les instances.
Pour chacun des services que vous avez inscrits dans le ServiceCollection, vous pouvez appeler la Add méthode directement avec une ServiceDescriptor instance. Prenons les exemples suivants :
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
Le code précédent équivaut à la façon dont le IConsole service a été inscrit dans le ServiceCollection. La Add méthode est utilisée pour ajouter une ServiceDescriptor instance qui décrit le IConsole service. La méthode statique ServiceDescriptor.Describe délègue à plusieurs constructeurs ServiceDescriptor. Considérez le code équivalent pour le IGreetingService service :
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
Le code précédent décrit le IGreetingService service avec son type de service, son type d’implémentation et sa durée de vie. Enfin, tenez compte du code équivalent pour le FarewellService service :
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
Le code précédent décrit le type concret FarewellService comme les types de service et d’implémentation. Le service est enregistré en tant que service singleton.