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
dans votre fichier .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
qui fait référence au fichier 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
qui pointe vers author.proto :
< 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