Introduction à gRPC dans .NET Core et .NET 5

   
gRPC est un framework RPC hautes performances qui permet efficacement le service- communication en service dans et entre les centres de données. Il prend également en charge la connexion d'appareils mobiles et de clients de navigateur aux services de backend. Il a été implémenté dans Google et plus tard en open-source, et c'est actuellement un projet d'incubation de la Cloud Native Computing Foundation (CNCF). Ses fonctionnalités incluent:
- Streaming bidirectionnel
- Sérialisation binaire puissante
- Authentification enfichable, équilibrage de charge et vérification de l'état
Si vous adoptez une architecture de microservice dans votre organisation, gRPC augmenterait probablement les performances du communication entre vos microservices.
Dans cet article, je vais vous montrer comment créer un service gRPC à l'aide de .NET Core 3.1 (ou version ultérieure). Je décomposerai quelques concepts fondamentaux importants de gRPC et inclurai également des étapes pour les faire pour les utilisateurs de Mac et VS Code.
Comme prérequis, je m'attends à une certaine familiarité avec C #, ASP.NET Core et Visual Studio ou VS Code.
Créer un serveur gRPC
Nous allons commencer par créer un nouveau projet dotnet avec le modèle de service gRPC.
 Si vous utilisez Visual Studio, créez un nouveau projet et sélectionnez le modèle  gRPC Service  . Utilisez  GrpcAuthor  comme nom du projet.
 Si vous utilisez VS Code, vous allez créer le projet à l'aide de  dotnet CLI  et l'ouvrir dans VS Code. Ouvrez votre application de ligne de commande (ou Terminal si vous êtes sur Mac) et exécutez la commande  dotnet new grpc -o GrpcAuthor . Ouvrez ensuite le projet dans VS Code en exécutant la commande  code -r GrpcAuthor .
The RPC Service Definition
Une application cliente gRPC peut appeler directement une méthode sur une application serveur comme s'il s'agissait d'un objet local. Les applications client et serveur se parlent en utilisant les tampons de protocole . Les tampons de protocole sont utilisés à la fois comme langage de définition d'interface (IDL) pour le service et comme format d'échange de messages sous-jacent.
 Une interface de service est définie dans un fichier  .proto  utilisant un tampon de protocole. Dans celui-ci, vous spécifiez les méthodes qui peuvent être appelées à distance avec leurs paramètres et leurs types de retour. Le serveur implémente cette interface et exécute un serveur gRPC pour gérer les appels clients. Le client, d'autre part, a un stub (appelé simplement un client dans certaines langues) qui fournit les mêmes méthodes que le serveur, et avec lui, le client appelle les méthodes du serveur comme si elles étaient locales à l'application. [19659007] Une fois le service défini, vous utilisez le compilateur de tampon de protocole  protoc  pour générer des classes d'accès / transfert de données à partir de votre fichier de définition de proto. Ce fichier contient l'implémentation des messages et des méthodes dans l'interface de service.
Le modèle utilisé pour créer le projet comprend déjà un fichier proto greet.proto qui se trouve dans le Protos dossier.
 syntaxe  =   "proto3" ; 
option csharp_namespace  =   "GrpcAuthor" ; 
paquet salue ; 
service Greeter  {
  
  rpc  SayHello   ( HelloRequest )   renvoie   ( HelloReply ) ; 
} 
message HelloRequest  {
   string  name  =   1 ; 
} 
message HelloReply  {
   string  message  =   1 ; 
} 
Décomposons le fichier proto afin de comprendre la syntaxe du tampon de protocole. [19659037] La définition de l'interface du service Greet
 syntax = "proto3";  Le spécificateur de syntaxe   est utilisé pour indiquer la version du tampon de protocole utilisée. Dans ce cas,  proto3 qui est la dernière version au moment de la rédaction de cet article et a plus de fonctionnalités et de support de langage que son prédécesseur.
 option csharp_namespace  =   "GrpcAuthor" ; 
package greet ; 
 L'option  spécificateur csharp_namespace  est utilisée pour spécifier l'espace de noms que les fichiers générés auront. Il est utilisé pour éviter les conflits de noms entre les types de messages de protocole, tout comme le spécificateur du package  . La façon dont le spécificateur de package   affecte le code généré dépend de la langue que vous utilisez. Pour C #, il est utilisé comme espace de noms sauf si vous fournissez une option  csharp_namespace . En Java, il est utilisé comme nom de package, sauf si vous spécifiez  option java_package  dans le fichier  .proto .
 message HelloRequest  {
   string  name  =   1 ; 
} 
message HelloReply  {
   string  message  =   1 ; 
} 
  HelloRequest  et  HelloReply  sont les structures de données qui seront utilisées pour échanger des informations entre le client et le serveur. Ils sont appelés  messages  et contiennent des paires nom-valeur appelées champs. Le numéro que vous voyez dans la définition de champ est un numéro unique utilisé pour identifier les champs lorsque le message est sérialisé vers Protobuf. En effet, la sérialisation d'un petit nombre est plus rapide que la sérialisation du nom de champ entier.
service Greeter  {
  rpc  SayHello   ( HelloRequest )   renvoie   ( HelloReply ) ; 
} 
 Ceci est la définition du service et il contient une méthode  SayHello  avec un paramètre et un type de retour comme tampon de protocole  messages .
 Afin de générer du code pour le fichier  .proto vous utilisez le compilateur  protoc  et le plugin C # pour générer le code serveur ou client. Cela sera fait pour vous en utilisant le package NuGet  Grpc.Tools . Les classes nécessaires sont générées automatiquement par le processus de construction. Il sait comment générer les types via le paramètre de groupe d'éléments  .csproj .
 < ItemGroup > 
   < Protobuf   Inclure  =  " Protos  greet.proto "    GrpcServices  =  " Server "    /> 
 </  ItemGroup >  
 Le code généré sait communiquer avec d'autres services / clients en utilisant des tampons de protocole. L'outillage C # génère le type  GreeterBase  qui sera utilisé comme classe de base pour implémenter le service gRPC.
Il existe une implémentation pour le service Greeter dans Services / GreeterService .cs :
  public   class   GreeterService  :  Greeter .  GreeterBase
 {
     privé   lecture seule  ILogger  < GreeterService >  _logger ; 
     public   GreeterService  ( ] ILogger  < GreeterService >  logger ) 
     {
        _logger  =  logger ; 
    } 
     public   override  Task  < HelloReply >   SayHello  ( HelloRequest request  ServerCallContext context ) 
     {
         return  Task .  FromResult  ( new   HelloReply [19659098] {
            Message  =   "Bonjour"   +  demande .  Nom
        } ) ; 
    } 
} 
 Le service est implémenté en héritant de la classe  Greeter.GreeterBase . Cette classe de base est générée au moment de la construction à l'aide du fichier  greet.proto .
Créer un nouveau service gRPC
Vous avez vu le service Greeter généré à partir du modèle de projet. Vous allez créer un nouveau service avec une méthode RPC pour obtenir un auteur de livre par son nom.
Ajoutez un nouveau fichier au dossier Protos nommé author.proto puis copiez et collez-y la définition de l'interface ci-dessous.
 syntaxe  =   "proto3" ; 
option csharp_namespace  =   "GrpcAuthor" ; 
auteur du package ; 
Auteur du service  {
  rpc  GetAuthor   ( AuthorRequest )   renvoie   ( AuthorResponse ) ; 
} 
message AuthorRequest  {
   string  name  =   1 ; 
} 
message BookReply  {
   string  title  =   1 ; 
} 
message AuthorResponse  {
   string  name  =   1 ; 
  répété BookReply books_authored  =   2 ; 
} 
 Dans cette définition de service, vous avez un service  Author  avec une méthode RPC  GetAuthor . Le message  AuthorResponse  contient les champs  name  et  books_authored . Le champ  books_authored  est un type composite de  BookReply . La règle de champ  répétée  est utilisée pour indiquer qu’il s’agit d’une collection; par conséquent, il peut être répété un nombre illimité de fois dans un message sérialisé.
 Maintenant que vous avez la définition du service, vous devez en informer votre projet afin qu'il génère le code nécessaire lors de la construction. Pour ce faire, mettez à jour le fichier  GrpcAuthor.csproj  pour inclure un groupe d'éléments avec un élément  author.proto .
 < ItemGroup > 
   < Protobuf   Inclure  =  " Protos  greet.proto "    GrpcServices  = [19659020] " Serveur "    /> 
   < Protobuf   Inclure  =  " Protos  author.proto "    GrpcServices  =  " Server "    /> 
 </  ItemGroup > 
Mettre en œuvre le service Définition
Après avoir créé le contrat de service, vous devez l'implémenter. Créez un nouveau fichier dans le dossier Services nommé AuthorService.cs . Copiez et collez le code ci-dessous.
  using  System ; 
 using  System .  Collections .  Generic  ]; 
 en utilisant  System .  Linq ; 
 using  System .  Threading .  Tasks ; 
 utilisant  Grpc .  Core ; 
 using  Microsoft .  Extensions .  Logging ; 
 ] namespace  GrpcAuthor
 {
     public   class   AuthorService  :  Author .  AuthorBase
     {
         private   readonly  ILogger  < AuthorService >  _logger ; 
         private  List  < ] AuthorResponse >  auteurs ; 
         public   AuthorService  ( ILogger  < AuthorService >  logger ) 
         {
            _logger  =  enregistreur ; 
            auteurs  =   nouvelle   Liste  < AuthorResponse >  () ; 
             var  antonio  = [19659078] nouveau   AuthorResponse   { Name  =   "Antonio Gonzalez"  } ; 
            antonio .  BooksAuthored .  Add  ( new   BookReply   { Title  =   "Beaucoup de bruit pour rien"  } ) ; 
            antonio .  BooksAuthored .  Add  ( new   BookReply   { Title  =   "Comment faire une scission "} ) ; 
            auteurs .  Add  ( antonio ) ; 
             var  jack  =   new   AuthorResponse   { Nom  =   "Jack Olabisi"  } ; 
            jack .  BooksAuthored .  Add  ( new   BookReply   { Title  =   "Early morning bird" [19659023]} ) ; 
            jack .  BooksAuthored .  Add  ( new   BookReply   { Title  =   "Fly me to Paris" } ) ; 
            auteurs .  Add  ( jack ) ; 
        } 
         public   override  Task  < AuthorResponse >   GetAuthor  ( AuthorRequest request  ServerCallContext context ) 
         {
             var  author  =  auteurs .  FirstOrDefault  ( x  = >  x .  Nom  ==  demande .  ] Nom ) ; 
             return  Task .  FromResult  ( author ) ; 
        } 
    } 
} 
 Le  AuthorService  hérite de  AuthorBase  qui sera généré automatiquement à partir de la définition du service. Ensuite, vous remplacez la méthode  GetAuthor  fournie par la classe de base. Dans cette méthode, nous recherchons dans la liste des auteurs en mémoire et retournons celui qui correspond au nom dans le paramètre  AuthorRequest .
Register the Service
 L'étape suivante consiste à enregistrer le service dans la configuration de l'application dans  StartUp.cs . Ouvrez  StartUp.cs accédez à la méthode  Configure  et ajoutez l'instruction de code ci-dessous après la ligne 34 et sous l'enregistrement du service pour  GreeterService :
 endpoints  ].  MapGrpcService  < AuthorService >   () ; 
Tester l'application
 À ce stade, vous disposez de tous les code nécessaire pour servir les services gRPC et tester si cela fonctionne. Cependant, les services gRPC ne peuvent passer que par des clients gRPC. Pour la démonstration de ce blog, vous allez créer une application console qui appellera la méthode  GetAuthor . Cependant, si vous créez l'application sur macOS ou Windows 7 et versions antérieures, Kestrel ne prend pas en charge HTTP / 2 avec TLS sur ces systèmes d'exploitation. Vous allez donc configurer un point de terminaison HTTP / 2 sans TLS dans  Program.cs  si vous utilisez l'un de ces systèmes d'exploitation.
 Ouvrez  Program.cs en ligne 23 et ajoutez l'instruction de code ci-dessous dans l'appel de méthode à  ConfigureWebHostDefaults 
  if   ( RuntimeInformation .  IsOSPlatform  ( OSPlatform .  OSX ) )   {
    webBuilder .  Configurer Kestrel  ( options  = > 
     {
        
        options .  ListenLocalhost  ( 5000  o  = >  o .  Protocols  = 
            HttpProtocols .  Http2 ) ; 
    } ) ; 
  } 
Puis ajoutez les instructions using suivantes:
  using  Microsoft .  AspNetCore .  Server .  Kestrel .  Core ; 
 using  System  using  System  ].  Runtime .  InteropServices ; 
Le code que vous avez ajouté permet de configurer un point de terminaison HTTP / 2 sans TLS pour Kestrel, si le programme s'exécute sous macOS. [19659007] Votre fichier Program.cs doit correspondre au code ci-dessous:
  using  System ; 
 using  System .  Collections .  Generic ; 
 using  System .  IO ; 
 using  System .  Linq  ; 
 en utilisant le système  .  Threading .  Tâches ; 
 avec  Microsoft .  AspNetCore .  Hébergement ; 
 avec  Microsoft  .  Extensions .  Hosting ; 
 using  Microsoft .  AspNetCore .  Server .  Kestrel .  Core ; 
 using  System .  Runtime .  InteropServices ; 
 namespace  GrpcAuthor
 {
     public   class   Program 
     {
         public   static   void   Main  ( string  [ ]]  args ) 
         {
             CreateHostBuilder  ( args ) .  Build  () ).  Exécutez  () ; 
        } 
        
        
         public   static  IHostBuilder  CreateHostBuilder  ( string  [ ]]  args )   = > 
            Hôte .  CreateDefaultBuilder  ( args ) 
                .  ConfigureWebHostDefaults  ( webBuilder  = > 
                 = > 
                 19659342] if   ( RuntimeInformation .  IsOSPlatform  ( OSPlatform .  OSX ) )   {
                     webBuilder .  ConfigurerKestrel  ( options  = > 
                      {
                         
                         options .  ListenLocalhost  ( 5000  o  = >  o .  Protocols  = 
                             HttpProtocols .  Http2 ) ; 
                     } ) ; 
                    } 
                    webBuilder .  UseStartup  < Startup >   () ; 
                } ) ; [19659086]} 
} 
Créez le client de console gRPC .NET
 Ouvrez une autre instance de Visual Studio et créez un nouveau projet de console nommé  GrpcAuthorClient . Vous pouvez également ajouter le nouveau projet au fichier de solution du projet précédent si vous le souhaitez. Si vous utilisez VS Code, ouvrez votre application de ligne de commande et exécutez  dotnet new console -o GrpcAuthorClient puis  code -r GrpcAuthorClient  pour l'ouvrir dans VS Code.
Puis installez les packages NuGet requis. Pour les utilisateurs de Visual Studio, ouvrez la fenêtre Package Manager Console et exécutez:
 Install-Package Grpc.Net.Client
Package d'installation Google.Protobuf
Install-Package Grpc.Tools
Pour les utilisateurs de VS Code, ouvrez le terminal intégré et exécutez
 dotnet add GrpcAuthorClient.csproj package Grpc.Net.Client
dotnet ajouter le package GrpcAuthorClient.csproj Google.Protobuf
dotnet ajouter le package GrpcAuthorClient.csproj Grpc.Tools
 Le package  Grpc.Net.Client  contient le client .NET Core, le package  Google.Protobuf  contient les API de message protobuf et la prise en charge des outils pour les fichiers protobuf se trouve dans le  Package Grpc.Tools .
Créez un dossier Protos puis copiez et collez le fichier author.proto depuis le projet serveur.
 Mise à jour  option csharp_namespace  valeur à  GrpcAuthorClient .
 Modifiez le fichier  GrpcAuthorClient.csproj  et ajoutez un groupe d'éléments avec un élément 
 < ItemGroup > 
   < Protobuf   Include  =  " Protos  author.proto  "   GrpcServices  = "  Client  "   /> 
 </  ItemGroup >  [19659036]Ouvert  Program.cs  et mettre à jour la méthode  Main ()  ce code: 
  static   async  Task  Main  ( string  []  args ) 
 {
     var  serverAddress  =   "https: // localhost: 5001" ; [19659081] if   ( RuntimeInformation .  IsOSPlatform  ( OSPlatform .  OSX ) )   {
        
        AppContext .  SetSwitch  (
             "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport"   true ) ; 
        serverAddress  =   "http: // localhost: 5000" ; 
    } 
     using   var  channel  =  GrpcChannel . [19659094] ForAddress  ( serverAddress ) ; 
     var  client  =    new   Author .  AuthorClient  ( channel ) ; 
     var  reply  =   wait  client .  GetAuthorAsync  ( new [19659079] AuthorRequest   { Name  =   "Antonio Gonzalez"  } ) ; 
    Console .  WriteLine  ( "Auteur:"   +  réponse .  ToString  () ) ) [19659020]; 
    Console .  WriteLine  ( "Appuyez sur n'importe quelle touche pour quitter ..." ) ; 
    Console .  ReadKey  () ; 
} 
 Le code crée  GrpcChannel  avec l'adresse du serveur. S'il s'exécute sur macOS, il configure l'application pour utiliser une connexion HTTP / 2 non sécurisée et définit l'URL du serveur sur l'URL HTTP non sécurisée. Si vous utilisez .NET 5, vous n’avez pas besoin de cette configuration supplémentaire. Il vous suffit de vous assurer que vous utilisez  Grpc.Net.Client  version 2.32.0 ou ultérieure.
 L'objet  GrpcChannel  est ensuite utilisé pour instancier le  AuthorClient . L'objet client est ensuite utilisé pour effectuer un appel asynchrone à l'aide de la méthode  GetAuthorAsync . Lorsque le serveur répond, le résultat est imprimé sur la console.
 Ajoutez les instructions using suivantes au fichier.
  using  System .  Net .  ] Http ; 
 utilisant le système  
.  Threading .  Tasks ; 
 using  Grpc .  Net .  Client ; 
 using  System .  Runtime .  InteropServices ; 
 Vous êtes maintenant prêt à tester le service. Démarrez d'abord le projet serveur en exécutant  dotnet run  dans le terminal intégré dans VS Code ou appuyez sur  Ctrl + F5  pour exécuter sans le débogueur dans Visual Studio. Au démarrage du serveur, exécutez le projet client  GrpcAuthorClient . Vous devriez obtenir le résultat suivant:
 Auteur:  {  "name" :   "Antonio Gonzalez"  "booksAuthored" :   [  {  "title" :   "Beaucoup de bruit pour rien"  }  {  "title" :   " Comment faire une scission " }  ]  } 
Appuyez sur n'importe quelle touche pour quitter  .. .
Résumé
gRPC est un framework RPC hautes performances avec des fonctionnalités d'authentification et d'équilibrage de charge enfichables. Vous définissez la manière dont vous souhaitez que vos données soient structurées à l'aide de tampons de protocole. Vous pouvez ensuite utiliser du code source généré automatiquement pour écrire et lire facilement vos données structurées vers et depuis divers flux de données et dans divers langages.
Dans cet article, vous avez appris à définir une interface de service à l'aide du tampon de protocole (version 3) et implémentez également le service en C #. En fin de compte, vous avez appris à créer un client gRPC et à appeler les méthodes sur le serveur.
Vous pouvez trouver le code source de ce message sur GitHub .
Ressources supplémentaires
Source link
