Services d'arrière-plan .NET Core
Apprenez à créer des services d'arrière-plan dans .NET Core à l'aide de l'hôte générique. L'hôte générique fournit des problèmes transversaux que vous connaissez bien dans ASP.NET Core, tels que l'injection de dépendance, la journalisation et la configuration. Cela vous permet de créer des processus longs pour des scénarios non HTTP.
.NET Core 2.1 a introduit l'hôte générique, qui vous permet de lancer une application similaire à celle d'ASP.NET Core, mais pour le traitement de requêtes non HTTP.
En d'autres termes, l'hôte générique prend toute la valeur offerte par ASP.NET Core pour des problèmes transversaux, tels que l'injection de dépendance intégrée, la journalisation et la configuration, et vous permet de s'appuyer sur celle-ci pour les systèmes non HTTP.
Le scénario le plus typique concerne un service de travail ou tout type de processus de longue durée. Cela pourrait être un service qui fait du travail, puis dort pendant un certain temps avant de faire plus de travail. Un exemple de ceci serait un service d'interrogation pour extraire des données d'un service Web externe. Un autre cas d'utilisation très courant serait un service qui extrait les messages d'une file d'attente et les traite.
Modèle de service pour le travailleur .NET Core 3
Avec .NET Core 3, un nouveau modèle est disponible, qui utilise l'hôte générique et vous donne l'échafaudage de base de la création d'un service de travail.
Si vous utilisez la CLI, vous pouvez générer facilement un nouveau travailleur de service:
nouveau travailleur dotnet MyWorkerServiceApp
Microsoft.Extensions.Hosting
La bibliothèque d'hôtes générique est le package Microsoft.Extensions.Hosting de NuGet
. Si vous ouvrez le fichier .csproj
généré par le modèle, le package sera également référencé. comme Microsoft.NET.Sdk.Worker
étant référencé:
netcoreapp3.0
les Program.cs
devraient vous paraître familiers si vous avez travaillé avec ASP.NET Core:
en utilisant le système;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
espace de noms WorkerServiceDemo
{
programme de classe publique
{
public static void Main (string [] args)
{
CreateHostBuilder (args) .Build (). Run ();
}
public statique IHostBuilder CreateHostBuilder (string [] args) =>
Host.CreateDefaultBuilder (args)
.ConfigureServices ((hostContext, services) =>
{
services.AddHostedService ();
});
}
}
Vous pouvez configurer divers services comme vous le feriez dans ASP.NET Core; Injection de dépendance via AddSingleton ()
ou AddTransient ()
; enregistrement via AddLogging ()
; ou configuration via AddOptions ()
.
La principale différence est dans ConfigureServices ()
où la nouvelle méthode d'extension, AddHostedService
s'appelle. Cela provient du paquet Microsoft.Extensions.Hosting.Abstractions et est une dépendance transitive de Microsoft.Extensions.Hosting
.
La nouvelle classe créée à partir du modèle est appelée Worker
et est utilisé comme paramètre de type dans AddHostedServices
.
à l'aide de System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
espace de noms WorkerServiceDemo
{
Classe publique Worker: BackgroundService
{
en lecture seule ILogger _logger;
travailleur public (enregistreur ILogger )
{
_logger = logger;
}
protégé remplacer async tâche ExecuteAsync (CancellationToken stoppingToken)
{
while (! stoppingToken.IsCancellationRequested)
{
_logger.LogInformation ("Travailleur exécuté à: {heure}", DateTimeOffset.Now);
attendez Task.Delay (1000, stoppingToken);
}
}
}
}
La première chose à noter est que notre classe étend la classe abstraite, BackgroundService
. Il s'agit d'une nouvelle classe fournie dans .NET Core 3. Elle implémente IHostedService
obligatoire pour AddHostedService
.
Avant de sauter dans BackgroundService
nous allons D'abord, jetez un coup d'oeil à IHostedService
et à ce qui doit être implémenté, si vous créez votre propre implémentation.
using System.Threading.Tasks;
espace de noms Microsoft.Extensions.Hosting
{
///
///
interface publique IHostedService
{
///
///
/// Indique que le processus de démarrage a été interrompu. Tâche démarrage asynchrone (annulationToken annulationToken);
///
///
/// Indique que le processus d'arrêt ne devrait plus être fluide. Task StopAsync (AnnulationToken annulationToken);
}
}
Vous devez simplement implémenter les méthodes StartAsync ()
et StopAsync ()
à l'aide des méthodes CancellationToken
pour un arrêt progressif de votre service.
You peut déjà déjà commencer à imaginer à quel point une classe abstraite serait utile, car la mise en oeuvre serait probablement similaire pour la plupart des scénarios dans lesquels vous souhaitez créer un service de longue durée.
BackgroundService
BackgroundService
est une nouveauté de .NET Core 3 et fournit une classe abstraite simple pour implémenter un service de longue durée.
using System;
using System.Threading;
using System.Threading.Tasks;
espace de noms Microsoft.Extensions.Hosting
{
///
/// Classe de base pour l'implémentation d'un Microsoft.Extensions.Hosting.IHostedService de longue durée.
///
classe abstraite publique BackgroundService: IHostedService, IDisposable
{
///
/// Cette méthode est appelée au démarrage de Microsoft.Extensions.Hosting.IHostedService. L'implémentation doit retourner une tâche qui représente
/// durée de vie de la longue opération en cours d'exécution.
///
/// Déclenché lorsque Microsoft.Extensions.Hosting.IHostedService.StopAsync (System.Threading.CancellationToken) est appelé.
/// A qui représente les opérations à long terme.
abstract Task protégé ExecuteAsync (AnnulationToken stoppingToken);
}
}
Vous devez simplement implémenter la tâche ExecuteAsync (CancellationToken stoppingToken)
lors de la gestion du CancellationToken
utilisé pour déterminer quand arrêter votre méthode à l'aide de System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
espace de noms WorkerServiceDemo
{
Classe publique Worker: BackgroundService
{
en lecture seule ILogger
travailleur public (enregistreur ILogger
{
_logger = logger;
}
protégé remplacer async tâche ExecuteAsync (CancellationToken stoppingToken)
{
while (! stoppingToken.IsCancellationRequested)
{
_logger.LogInformation ("Travailleur exécuté à: {heure}", DateTimeOffset.Now);
attendez Task.Delay (1000, stoppingToken);
}
}
}
}
Vous remarquerez que le constructeur prend un ILogger
comme dépendance, qui est résolu par l'injection de dépendance intégrée de l'hôte générique. Comme indiqué, nous pouvons définir d'autres services à enregistrer auprès de DI dans la méthode ConfigureServices ()
dans Program.cs
.
Le service de scrutation du taux de change
Pour un exemple simple, Je vais créer un service qui passe un appel HTTP toutes les heures sur un service Web de taux de change pour obtenir le dernier taux de change entre USD et CAD.
Packages
J'ajoute la dernière version de Microsoft.Extensions.Http
qui nous permet d'enregistrer le IHttpClientFactory
et d'enregistrer le Newtonsoft.Json
pour désérialiser la réponse JSON du service Web.
netcoreapp3.0
Configurer les services
Comme mentionné, j'appelle AddHttpClient ()
pour enregistrer le IHttpClientFactory
que je peux injecter dans ma classe de travailleurs:
à l'aide de Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
espace de noms WorkerServiceDemo
{
programme de classe publique
{
public static void Main (string [] args)
{
CreateHostBuilder (args) .Build (). Run ();
}
public statique IHostBuilder CreateHostBuilder (string [] args) =>
Host.CreateDefaultBuilder (args)
.ConfigureServices ((hostContext, services) =>
{
services.AddHttpClient ();
services.AddHostedService ();
});
}
}
Travailleur
La première chose est IHttpClientFactory
afin que nous puissions obtenir une nouvelle instance de HttpClient. Si vous ne connaissez pas bien le IHttpClientFactory
consultez la documentation .
Dans le ExecuteAsync
je vais adresser une requête HTTP au. api.exchangeratesapi.io
service et obtenez le dernier taux de change entre USD et CAD. Je vais gérer les échecs pertinents et utiliser l'enregistreur pour la sortie. Probablement ici, je stockerais ces données et les conserverais quelque part pour que mon application puisse les utiliser.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
espace de noms WorkerServiceDemo
{
Classe publique Worker: BackgroundService
{
chaîne de const privé Symbol = "CAD";
private const int ThreadDelay = 5000;
privé en lecture seule ILogger _logger;
lecture seule privée HttpClient _httpClient;
lecture seule privée JsonSerializer _serializer;
travailleur public (enregistreur ILogger httpttient IHttpClientFactory)
{
_logger = logger;
_httpClient = httpClient.CreateClient ();
_serializer = new JsonSerializer ();
}
protégé remplacer async tâche ExecuteAsync (CancellationToken stoppingToken)
{
while (! stoppingToken.IsCancellationRequested)
{
_logger.LogInformation ("Travailleur exécuté à: {heure}", DateTimeOffset.Now);
essayer
{
var response = wait _httpClient.GetAsync ($ "https://api.exchangeratesapi.io/latest?base=USD&symbols={Symbol}", stoppingToken);
if (response.IsSuccessStatusCode == false)
{
_logger.LogCritical ("Échec de l'API Exchange Rate avec le code d'état HTTP {statusCode} à: {heure}", response.StatusCode, DateTimeOffset.Now);
continuer;
}
using var sr = new StreamReader (attend la réponse.Content.ReadAsStreamAsync ());
using var jsonTextReader = new JsonTextReader (sr);
var exchangeRateResult = _serializer.Deserialize (jsonTextReader);
if (exchangeRateResult.Rates.TryGetValue (Symbol, out var cadValue))
{
_logger.LogInformation ($ "{Symbol} = {cadValue}");
}
autre
{
_logger.LogCritical ($ "Le taux de change en CAD n'a pas été renvoyé par l'API.");
}
}
catch (HttpRequestException ex)
{
_logger.LogCritical ($ "{nameof (HttpRequestException)}: {ex.Message}");
}
attendre Task.Delay (ThreadDelay, stoppingToken);
}
}
}
Classe publique CurrencyExchange
{
chaîne publique Base {get; ensemble; }
public DateTime Date {get; ensemble; }
Dictionnaire public Tarifs {get; ensemble; }
}
}
Service Windows
Si vous exécutez .NET Core sous Windows, vous pouvez installer ce service de travail en tant que service Windows.
Ajoutez le package Microsoft.Extensions.Hosting.WindowsServices
. dans votre .csproj
en tant que PackageReference
Ceci ajoute une méthode d'extension appelée UseWindowsService ()
à IHostBuilder
.
public statique IHostBuilder CreateHostBuilder (chaîne ) =>
Host.CreateDefaultBuilder (args)
.UseWindowsService ()
.ConfigureServices ((hostContext, services) =>
{
services.AddHttpClient ();
services.AddHostedService ();
});
Cela vous permet d’exécuter l’application en tant qu’application console ou de la déboguer normalement, à l’aide de la CLI, de Visual Studio, du code Visual Studio, de Rider, etc. Cependant, elle permet également d’installer (et puis exécutez-le en tant que service Windows).
cs create WorkerServiceDemo binPath = C: Chemin To WorkerServiceDemo.exe
Résumé
L’hôte générique et le nouveau BackgroundService
dans .NET. Core 3 fournit un moyen pratique de créer des processus de longue durée dans .NET. Vous bénéficiez de toutes les fonctionnalités merveilleuses d'injection de dépendance, de journalisation et de configuration auxquelles vous êtes habitué dans ASP.NET Core pour l'exécution de travaux ou de services de longue durée.
Source link