Fermer

août 16, 2019

Services d'arrière-plan .NET Core


.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 où T: class, IHostedService 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
{
  ///

  /// Définit les méthodes pour les objets gérés par l'hôte.
  ///

  interface publique IHostedService
  {
    ///

    /// Déclenché lorsque l'hôte de l'application est prêt à démarrer le service.
    ///

    /// Indique que le processus de démarrage a été interrompu.     Tâche démarrage asynchrone (annulationToken annulationToken);

    ///

    /// Déclenché lorsque l'hôte de l'application effectue un arrêt progressif.
    ///

    /// 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 _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);
      }
    }
  }
}

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