Fondamentaux • Hôte générique
Pourquoi faire ?
L’hôte générique est un outil puissant que nous propose le framework .NET via l’assembly Microsoft.Extensions.Hosting.
Il facilite notre vie de développeur en prenant en charge :
- le cycle de vie de l’application : démarrage, arrêt
- la gestion des services en arrière-plan
IHostedService - l’injection de dépendances Dependencies Injection
- la configuration
- la journalisation
ILogger<>
Mise en place
Commençons par créer un nouveau projet console. Il nous servira de base de travail.
dotnet new console --name=ConsoleProjectAjoutons le paquet Nuget Microsoft.Extensions.Hosting.
cd ConsoleProjectdotnet add package Microsoft.Extensions.HostingNous pouvons maintenant ouvrir le projet ConsoleProject dans notre IDE favori.
Hôte générique par défaut
L’hôte générique par défaut sert de base à tous ses dérivés. Ces derniers l’améliorent et l’enrichissent.
Créons le constructeur d’hôte générique par défaut.
using Microsoft.Extensions.Hosting;
// See https://aka.ms/new-console-template for more informationConsole.WriteLine("Hello, World!");
IHostBuilder builder = Host.CreateDefaultBuilder(args);Beaucoup de choses sont faites par la méthode CreateDefaultBuilder() :
- définition de la racine du contenu ;
- chargement de la configuration ;
- ajout des fournisseurs de journalisation.
Définition de la racine du contenu
La racine du contenu est définie par le dossier courant GetCurrentDirectory(). Qu’est-ce-que cela signifie ?
Le dossier courant est celui où est situé l’exécutable. Par exemple si nous exécutons notre projet en mode debug alors le dossier courant sera : ./bin/Debug/net8.0.
Si nous souhaitons accéder à des fichiers (comme appsettings.json par exemple) depuis notre application, il faudra alors bien penser à spécifier l’action de compilation Content dans les propriétés du fichier.

Chargement de la configuration
La configuration de l’hôte et la configuration de l’application sont chargées. Une vue d’ensemble est présentée dans l’article Configuration .NET.
Sans entrer dans le détail des différences entre configuration de l’hôte et configuration de l’application, ce qui nous intéresse est que plusieurs sources de configuration sont prises en compte et fusionnées :
- les variables d’environnement ;
- les arguments de la ligne de commande ;
- le fichier
appsettings.json; - le fichier
appsettings.[ENV].json; - le gestionnaire de secrets (quand l’application est lancée dans l’environnement
Development) ; - tout autre fournisseur de configuration personnalisé.
Ajout des fournisseurs de journalisation (logger)
Les fournisseurs de journalisation sont ajoutés :
- Console
- Debugger
- EventSource
- EventLog (uniquement pour Windows)
Ces fournisseurs peuvent être paramétrés dans le fichier appsettings.json :
{ "Logging": { "LogLevel": { "Default": "Information" }, "Console": { "Default": "Warning" }, "Debug": { "Default": "Trace" } }}Configuration des services de l’hôte
Une fois que le constructeur d’hôte par défaut est créé, nous avons la possibilité d’ajouter des services au conteneur de l’hôte via la méthode ConfigureServices(). Mais qu’est-ce-que cela signifie exactement ?
Cette méthode nous permet de paramétrer l’injection de dépendances en ajoutant des nouvelles entrées dans le conteneur, c’est-à-dire des nouveaux services dans le vocabulaire utilisé par .NET.
Un certain nombre existent déjà : les services de configuration et de journalisation que nous venons juste de détailler. Mais il est possible d’en ajouter des nouveaux : des services fournis par .NET, ceux amenés par des paquets NuGet et bien entendu nos propres services.
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // → Ajout de SingletonService dans le conteneur d'injection de dépendances services.AddSingleton(new SingletonService("3ddf09bndk3bnf0r5h"));});
// ...
internal record SingletonService(string Key);Construction de l’hôte
Une fois que l’hôte a été créé et configuré, il est alors possible de le construire via la méthode Build();
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // → Ajout de SingletonService dans le conteneur d'injection de dépendances services.AddSingleton(new SingletonService("3ddf09bndk3bnf0r5h"));});
IHost host = builder.Build();
internal record SingletonService(string Key);Une fois construit, l’hôte a accès à une instance de IServiceProvider via la propriété Services. Cela nous donne accès à tous les services paramétrés dans le conteneur d’injection de dépendances.
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // → Ajout de SingletonService dans le conteneur d'injection de dépendances services.AddSingleton(new SingletonService("3ddf09bndk3bnf0r5h"));});
IHost host = builder.Build();var singletonService = host.Services.GetRequiredService<SingletonService>();
internal record SingletonService(string Key);Démarrage et arrêt de l’hôte
Une fois l’hôte construit, il est possible de le démarrer et de l’arrêter.
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // ...});
IHost host = builder.Build();
// → Démarrage de l'hôteawait host.StartAsync();
// → Lecture de la touche tapée dans la consoleConsole.ReadKey();
// → Arrêt de l'hôteawait host.StopAsync();
// ...Ajout de IHostedService
Un IHostedService est un service qui est démarré et arrêté en même temps que l’hôte.
La classe qui l’implémente doit hériter de l’interface IHostedService. Nous pouvons ajouter cette classe conteneur d’injection de dépendances via la méthode AddHostedService().
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // ...
// → Ajout de MyHostedService dans le conteneur d'injection de dépendances en tant qu'HostedService services.AddHostedService<MyHostedService>();});
// ...
internal class MyHostedService(ILogger<MyHostedService> logger) : IHostedService{ private readonly ILogger<MyHostedService> _logger = logger ?? throw new ArgumentNullException(nameof(logger));
public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("MyHostedService started"); return Task.CompletedTask; }
public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("MyHostedService stopped"); return Task.CompletedTask; }}Au démarrage de l’hôte, la méthode IHostedService.StartAsync() est appelée pour tous les services enregistrés via AddHostedService(). Et à l’arrêt de l’hôte, c’est la méthode IHostedService.StopAsync() qui est appelée pour tous les HostedServices.
Chaque HostedService peut avoir sa logique propre et injecter toutes les dépendances dont il a besoin. Dans notre cas, nous avons injecté le service de journalisation.
BackgroundService
La classe abstraite BackgroundService implémente l’interface IHostedService et propose la méthode ExecuteAsync().
Cette méthode contient la logique à exécuter et elle est lancée au démarrage de l’hôte.
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>{ // ...
// → Ajout de MyBackgroundService dans le conteneur d'injection de dépendances en tant qu'HostedService services.AddHostedService<MyBackgroundService>();});
// ...
internal class MyBackgroundService(ILogger<MyBackgroundService> logger) : BackgroundService{ private readonly ILogger<MyBackgroundService> _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private PeriodicTimer? _timer;
protected override async Task ExecuteAsync(CancellationToken cancellationToken) { _logger.LogInformation("MyBackgroundService started"); _timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); while (!cancellationToken.IsCancellationRequested && await timer.WaitForNextTickAsync(cancellationToken)) { _logger.LogInformation("MyBackgroundService pings at {now}", DateTimeOffset.Now); } }
public override void Dispose() { _timer?.Dispose(); _logger.LogInformation("MyBackgroundService stopped"); }}Dans notre exemple :
- Au démarrage de l’hôte la méthode
MyBackgroundService.ExecuteAsync()est appelée ; - Le message d’information “MyBackgroundService started” est émis par le service de journalisation ;
- Au bout de 5 secondes et toutes les 5 secondes, le message d’information “MyBackgroundService pings at {now}” est émis, où
{now}est égal à l’heure courante ; - À l’arrêt de l’hôte, la boucle
whileest stoppée via leCancellationToken; - La méthode
Dispose()est appelée : lePeriodicTimerest libéré et le message “MyBackgroundService stopped” est émis.
Pour aller plus loin
Nous avons vu ensemble comment créer, paramétrer, construire, démarrer et arrêter un hôte par défaut. Nous connaissons le fonctionnement d’une brique essentielle au fonctionnement de nombreuses applications .NET.
Il existe également d’autres constructeurs d’hôte fournis par .NET dérivant de celui de l’hôte par défaut. Voici les deux qui seront souvent utilisés :
- HostApplicationBuilder souvent utilisé à la place de
IHostBuilder; - WebApplicationBuilder (assembly
Microsoft.AspNetCore) utilisé dans les application web ASP.NET.
Microsoft propose une documentation complète sur ce sujet (et bien d’autres). N’hésitez pas à la consulter pour approfondir ou éclaircir certains points.