Aufrufen von gRPC-Diensten mithilfe eines .NET-ClientsCall gRPC services with the .NET client

Im NuGet-Paket Grpc.Net.Client ist eine .NET-gRPC-Clientbibliothek verfügbar.A .NET gRPC client library is available in the Grpc.Net.Client NuGet package. Im vorliegenden Dokument wird Folgendes erläutert:This document explains how to:

  • Konfigurieren eines gRPC-Clients, um gRPC-Dienste aufzurufenConfigure a gRPC client to call gRPC services.
  • Durchführen von gRPC-Aufrufe von unären, Serverstreaming- und Clientstreamingmethoden sowie von Methoden für bidirektionales Streaming.Make gRPC calls to unary, server streaming, client streaming, and bi-directional streaming methods.

Konfigurieren eines gRPC-ClientsConfigure gRPC client

gRPC-Clients sind konkrete Clienttypen, die aus *.proto Dateien generiert werden.gRPC clients are concrete client types that are generated from *.proto files. Der konkrete gRPC-Client verfügt über Methoden, die in den gRPC-Dienst in der *.proto-Datei übersetzt werden.The concrete gRPC client has methods that translate to the gRPC service in the *.proto file. Beispielsweise generiert ein Dienst namens Greeter einen GreeterClient-Typ mit Methoden zum Aufrufen des Diensts.For example, a service called Greeter generates a GreeterClient type with methods to call the service.

Ein gRPC-Client wird aus einem Kanal erstellt.A gRPC client is created from a channel. Starten Sie das Erstellen eines Kanals mithilfe von GrpcChannel.ForAddress, und verwenden Sie dann den Kanal, um einen gRPC-Client zu erstellen:Start by using GrpcChannel.ForAddress to create a channel, and then use the channel to create a gRPC client:

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greet.GreeterClient(channel);

Ein Kanal steht für eine langlebige Verbindung zu einem gRPC-Dienst.A channel represents a long-lived connection to a gRPC service. Wenn ein Kanal erstellt wird, wird er mit Optionen zum Aufrufen eines Diensts konfiguriert.When a channel is created, it's configured with options related to calling a service. Die für Aufrufe verwendete Klasse HttpClient, die maximale Größe für gesendete und empfange Nachrichten sowie die Protokollierung können in der Klasse GrpcChannelOptions angegeben und mit GrpcChannel.ForAddress verwendet werden.For example, the HttpClient used to make calls, the maximum send and receive message size, and logging can be specified on GrpcChannelOptions and used with GrpcChannel.ForAddress. Eine vollständige Liste der Optionen finden Sie unter Konfigurieren von Clientoptionen.For a complete list of options, see client configuration options.

var channel = GrpcChannel.ForAddress("https://localhost:5001");

var greeterClient = new Greet.GreeterClient(channel);
var counterClient = new Count.CounterClient(channel);

// Use clients to call gRPC services

Konfigurieren von TLSConfigure TLS

Die Sicherheit auf Verbindungsebene von gRPC-Client und dem aufgerufenen Dienst muss übereinstimmen.A gRPC client must use the same connection-level security as the called service. Beim Erstellen des gRPC-Kanals wird für den gRPC-Client die Verwendung von Transport Layer Security (TLS) konfiguriert.gRPC client Transport Layer Security (TLS) is configured when the gRPC channel is created. Ein gRPC-Client löst einen Fehler aus, wenn beim Aufrufen eines Diensts die Sicherheit auf Verbindungsebene von Kanal und nicht Dienst nicht übereinstimmen.A gRPC client throws an error when it calls a service and the connection-level security of the channel and service don't match.

Stellen Sie beim Konfigurieren eines gRPC-Kanals für die Verwendung von TLS sicher, dass die Serveradresse mit https beginnt.To configure a gRPC channel to use TLS, ensure the server address starts with https. GrpcChannel.ForAddress("https://localhost:5001") verwendet beispielsweise das HTTPS-Protokoll.For example, GrpcChannel.ForAddress("https://localhost:5001") uses HTTPS protocol. Der gRPC-Kanal handelt automatisch eine mit TLS gesicherte Verbindung aus und verwendet für gRPC-Aufrufe eine sichere Verbindung.The gRPC channel automatically negotiates a connection secured by TLS and uses a secure connection to make gRPC calls.

Tipp

gRPC unterstützt die Authentifizierung mit Clientzertifikaten über TLS.gRPC supports client certificate authentication over TLS. Informationen zum Konfigurieren von Clientzertifikaten mit einem gRPC-Kanal finden Sie unter Authentifizierung und Autorisierung in gRPC für ASP.NET Core.For information on configuring client certificates with a gRPC channel, see Authentifizierung und Autorisierung in gRPC für ASP.NET Core.

Stellen Sie zum Aufrufen von unsicheren gRPC-Diensten sicher, dass die Serveradresse mit http beginnt.To call unsecured gRPC services, ensure the server address starts with http. GrpcChannel.ForAddress("http://localhost:5000") verwendet beispielsweise das HTTP-Protokoll.For example, GrpcChannel.ForAddress("http://localhost:5000") uses HTTP protocol. Wenn Sie unsichere gRPC-Dienste mit dem .NET-Client aufrufen möchten, sind ab .NET Core 3.1 weitere Konfigurationen erforderlich.In .NET Core 3.1 or later, additional configuration is required to call insecure gRPC services with the .NET client.

ClientleistungClient performance

Kanal- und Clientleistung und -nutzung:Channel and client performance and usage:

  • Das Erstellen eines Kanals kann ein kostspieliger Vorgang sein.Creating a channel can be an expensive operation. Wenn ein Kanal für gRPC-Aufrufe wiederverwendet wird, stehen Leistungsvorteile zur Verfügung.Reusing a channel for gRPC calls provides performance benefits.
  • gRPC-Clients werden mit Kanälen erstellt.gRPC clients are created with channels. Bei gRPC-Clients handelt es sich um Lightweightobjekte. Sie müssen nicht zwischengespeichert oder wiederverwendet werden.gRPC clients are lightweight objects and don't need to be cached or reused.
  • Aus einem Kanal können mehrere gRPC-Clients erstellt werden, einschließlich verschiedener Clienttypen.Multiple gRPC clients can be created from a channel, including different types of clients.
  • Ein Kanal und Clients, die aus dem Kanal erstellt wurden, können sicher von mehreren Threads verwendet werden.A channel and clients created from the channel can safely be used by multiple threads.
  • Clients, die aus dem Kanal erstellt wurden, können mehrere gleichzeitige Aufrufe durchführen.Clients created from the channel can make multiple simultaneous calls.

GrpcChannel.ForAddress ist nicht die einzige Option für das Erstellen eines gRPC-Clients.GrpcChannel.ForAddress isn't the only option for creating a gRPC client. Wenn Sie gRPC-Dienste in einer ASP.NET Core-App aufrufen, sollten Sie die Integration der gRPC-Clientfactory in Erwägung ziehen.If calling gRPC services from an ASP.NET Core app, consider gRPC client factory integration. Die gRPC-Integration mit HttpClientFactory bietet eine zentralisierte Alternative zur Erstellung von gRPC-Clients.gRPC integration with HttpClientFactory offers a centralized alternative to creating gRPC clients.

Hinweis

Das Aufrufen von gRPC über HTTP/2 mit Grpc.Net.Client wird in Xamarin aktuell nicht unterstützt.Calling gRPC over HTTP/2 with Grpc.Net.Client is currently not supported on Xamarin. Die HTTP/2-Unterstützung soll jedoch in einem zukünftigen Release von Xamarin optimiert werden.We are working to improve HTTP/2 support in a future Xamarin release. Grpc.Core und gRPC-Web sind funktionsfähige Alternativen, die aktuell verwendet werden können.Grpc.Core and gRPC-Web are viable alternatives that work today.

Durchführen von gRPC-AufrufenMake gRPC calls

Ein gRPC-Aufruf wird initiiert, indem eine Methode auf dem Client aufgerufen wird.A gRPC call is initiated by calling a method on the client. Der gRPC-Client verarbeitet die Nachrichtenserialisierung und leitet den gRPC-Aufruf an den entsprechenden Dienst weiter.The gRPC client will handle message serialization and addressing the gRPC call to the correct service.

Bei gRPC stehen verschiedene Methodentypen zur Verfügung.gRPC has different types of methods. Wie der Client verwendet wird, um einen gRPC-Aufruf durchzuführen, hängt vom Typ der aufgerufenen Methode ab.How the client is used to make a gRPC call depends on the type of method called. Es gibt die folgenden gRPC-Methodentypen:The gRPC method types are:

  • UnärUnary
  • ServerstreamingServer streaming
  • ClientstreamingClient streaming
  • Bidirektionales StreamingBi-directional streaming

Unärer AufrufUnary call

Ein unärer Aufruf beginnt damit, dass der Client eine Anforderungsnachricht sendet.A unary call starts with the client sending a request message. Sobald der Dienst abgeschlossen ist, wird eine Antwortnachricht zurückgegeben.A response message is returned when the service finishes.

var client = new Greet.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });

Console.WriteLine("Greeting: " + response.Message);
// Greeting: Hello World

Alle unären Dienstmethoden in der Datei *.proto führen zu zwei .NET-Methoden auf dem konkreten gRPC-Clienttyp, um die Methode aufzurufen: eine asynchrone Methode und eine blockierende Methode.Each unary service method in the *.proto file will result in two .NET methods on the concrete gRPC client type for calling the method: an asynchronous method and a blocking method. Bei GreeterClient gibt es beispielsweise zwei Möglichkeiten, SayHello aufzurufen:For example, on GreeterClient there are two ways of calling SayHello:

  • GreeterClient.SayHelloAsync ruft den Greeter.SayHello-Dienst asynchron auf undGreeterClient.SayHelloAsync - calls Greeter.SayHello service asynchronously. kann erwartet werden.Can be awaited.
  • GreeterClient.SayHello ruft den Greeter.SayHello-Dienst auf und blockiert, bis der Vorgang abgeschlossen ist.GreeterClient.SayHello - calls Greeter.SayHello service and blocks until complete. Verwenden Sie diese Möglichkeit nicht für asynchronen Code.Don't use in asynchronous code.

ServerstreamingaufrufServer streaming call

Ein Serverstreamingaufruf beginnt damit, dass der Client eine Anforderungsnachricht sendet.A server streaming call starts with the client sending a request message. ResponseStream.MoveNext() liest Nachrichten, die vom Dienst gestreamt werden.ResponseStream.MoveNext() reads messages streamed from the service. Der Serverstreamingaufruf ist abgeschlossen, wenn ResponseStream.MoveNext() false zurückgibt.The server streaming call is complete when ResponseStream.MoveNext() returns false.

var client = new Greet.GreeterClient(channel);
using var call = client.SayHellos(new HelloRequest { Name = "World" });

while (await call.ResponseStream.MoveNext())
{
    Console.WriteLine("Greeting: " + call.ResponseStream.Current.Message);
    // "Greeting: Hello World" is written multiple times
}

Wenn Sie C# 8 oder höher verwenden, kann die await foreach-Syntax verwendet werden, um Nachrichten zu lesen.When using C# 8 or later, the await foreach syntax can be used to read messages. Die IAsyncStreamReader<T>.ReadAllAsync()-Erweiterungsmethode liest alle Nachrichten aus dem Antwortstream:The IAsyncStreamReader<T>.ReadAllAsync() extension method reads all messages from the response stream:

var client = new Greet.GreeterClient(channel);
using var call = client.SayHellos(new HelloRequest { Name = "World" });

await foreach (var response in call.ResponseStream.ReadAllAsync())
{
    Console.WriteLine("Greeting: " + response.Message);
    // "Greeting: Hello World" is written multiple times
}

ClientstreamingaufrufClient streaming call

Ein Clientstreamingaufruf beginnt, ohne dass der Client eine Nachricht sendet.A client streaming call starts without the client sending a message. Der Client kann Nachrichten mit RequestStream.WriteAsync senden.The client can choose to send messages with RequestStream.WriteAsync. Wenn der Client das Senden von Nachrichten abgeschlossen hat, sollte RequestStream.CompleteAsync() aufgerufen werden, damit der Dienst benachrichtigt wird.When the client has finished sending messages, RequestStream.CompleteAsync() should be called to notify the service. Der Aufruf ist abgeschlossen, wenn der Dienst eine Antwortnachricht zurückgibt.The call is finished when the service returns a response message.

var client = new Counter.CounterClient(channel);
using var call = client.AccumulateCount();

for (var i = 0; i < 3; i++)
{
    await call.RequestStream.WriteAsync(new CounterRequest { Count = 1 });
}
await call.RequestStream.CompleteAsync();

var response = await call;
Console.WriteLine($"Count: {response.Count}");
// Count: 3

Aufruf von bidirektionalem StreamingBi-directional streaming call

Ein Aufruf für bidirektionales Streaming beginnt, ohne dass der Client eine Nachricht sendet.A bi-directional streaming call starts without the client sending a message. Der Client kann Nachrichten mit RequestStream.WriteAsync senden.The client can choose to send messages with RequestStream.WriteAsync. Auf vom Dienst gestreamte Nachrichten kann mit ResponseStream.MoveNext() oder ResponseStream.ReadAllAsync() zugegriffen werden.Messages streamed from the service are accessible with ResponseStream.MoveNext() or ResponseStream.ReadAllAsync(). Der Aufruf für bidirektionales Streaming ist abgeschlossen, wenn ResponseStream keine weiteren Nachrichten mehr hat.The bi-directional streaming call is complete when the ResponseStream has no more messages.

var client = new Echo.EchoClient(channel);
using var call = client.Echo();

Console.WriteLine("Starting background task to receive messages");
var readTask = Task.Run(async () =>
{
    await foreach (var response in call.ResponseStream.ReadAllAsync())
    {
        Console.WriteLine(response.Message);
        // Echo messages sent to the service
    }
});

Console.WriteLine("Starting to send messages");
Console.WriteLine("Type a message to echo then press enter.");
while (true)
{
    var result = Console.ReadLine();
    if (string.IsNullOrEmpty(result))
    {
        break;
    }

    await call.RequestStream.WriteAsync(new EchoMessage { Message = result });
}

Console.WriteLine("Disconnecting");
await call.RequestStream.CompleteAsync();
await readTask;

Um die beste Leistung zu erzielen und unnötige Fehler beim Client und beim Dienst zu vermeiden, versuchen Sie, bidirektionale Streamingaufrufe ordnungsgemäß abzuschließen.For best performance, and to avoid unnecessary errors in the client and service, try to complete bi-directional streaming calls gracefully. Ein bidirektionaler Aufruf wird ordnungsgemäß abgeschlossen, wenn der Server das Lesen des Anforderungsdatenstroms und der Client das Lesen des Antwortdatenstroms beendet hat.A bi-directional call completes gracefully when the server has finished reading the request stream and the client has finished reading the response stream. Der vorherige Beispielaufruf ist ein Beispiel für einen bidirektionalen Aufruf, der ordnungsgemäß beendet wird.The preceding sample call is one example of a bi-directional call that ends gracefully. Im Aufruf führt der Client die folgenden Aktionen aus:In the call, the client:

  1. Er startet einen neuen bidirektionalen Streamingaufruf, indem EchoClient.Echo aufgerufen wird.Starts a new bi-directional streaming call by calling EchoClient.Echo.
  2. Er erstellt einen Hintergrundtask zum Lesen von Nachrichten aus dem Dienst mit ResponseStream.ReadAllAsync().Creates a background task to read messages from the service using ResponseStream.ReadAllAsync().
  3. Er sendet Nachrichten mit RequestStream.WriteAsync an den Server.Sends messages to the server with RequestStream.WriteAsync.
  4. Er benachrichtigt den Server, dass das Senden von Nachrichten mit RequestStream.CompleteAsync() abgeschlossen wurde.Notifies the server it has finished sending messages with RequestStream.CompleteAsync().
  5. Er wartet, bis der Hintergrundtask alle eingehenden Nachrichten gelesen hat.Waits until the background task has read all incoming messages.

Während des Aufrufs von bidirektionalem Streaming können sich Client und Dienst jederzeit gegenseitig Nachrichten senden.During a bi-directional streaming call, the client and service can send messages to each other at any time. Die beste Clientlogik für die Interaktion mit einem bidirektionalem Aufruf variiert je nach Dienstlogik.The best client logic for interacting with a bi-directional call varies depending upon the service logic.

Zugreifen auf gRPC-HeaderAccess gRPC headers

gRPC-Aufrufe geben Antwortheader zurück.gRPC calls return response headers. HTTP-Antwortheader übergeben Name/Wert-Metadaten über einen Befehl, der nicht mit der zurückgegebenen Nachricht verknüpft ist.HTTP response headers pass name/value metadata about a call that isn't related the returned message.

Auf Header kann über ResponseHeadersAsync zugegriffen werden, wodurch eine Sammlung von Metadaten zurückgegeben wird.Headers are accessible using ResponseHeadersAsync, which returns a collection of metadata. Da Header in der Regel mit der Antwortnachricht zurückgegeben werden, müssen Sie darauf warten.Headers are typically returned with the response message; therefore, you must await them.

var client = new Greet.GreeterClient(channel);
using var call = client.SayHelloAsync(new HelloRequest { Name = "World" });

var headers = await call.ResponseHeadersAsync;
var myValue = headers.GetValue("my-trailer-name");

var response = await call.ResponseAsync;

Verwendung von ResponseHeadersAsync:ResponseHeadersAsync usage:

  • Auf das Ergebnis von ResponseHeadersAsync muss gewartet werden, um die Headersammlung zu erhalten.Must await the result of ResponseHeadersAsync to get the headers collection.
  • Darauf muss nicht vor ResponseAsync (oder den Antwortstream beim Streaming) zugegriffen werden.Doesn't have to be accessed before ResponseAsync (or the response stream when streaming). Wenn eine Antwort zurückgegeben wurde, gibt ResponseHeadersAsync umgehend Header zurück.If a response has been returned, then ResponseHeadersAsync returns headers instantly.
  • Löst eine Ausnahme aus, wenn eine Verbindung bestand, oder Serverfehler und Header nicht für den gRPC-Aufruf zurückgegeben wurden.Will throw an exception if there was a connection or server error and headers weren't returned for the gRPC call.

Zugreifen auf gRPC-NachspanneAccess gRPC trailers

gRPC-Aufrufe können Antwortnachspanne zurückgeben.gRPC calls may return response trailers. Nachspanne werden verwendet, um Name/Wert-Metadaten zu einem Aufruf bereitzustellen.Trailers are used to provide name/value metadata about a call. Nachspanne stellen eine ähnliche Funktionalität wie HTTP-Header bereit, werden aber am Ende des Aufrufs empfangen.Trailers provide similar functionality to HTTP headers, but are received at the end of the call.

Auf Nachspanne kann über GetTrailers() zugegriffen werden, die eine Sammlung von Metadaten zurückgibt.Trailers are accessible using GetTrailers(), which returns a collection of metadata. Nach dem Abschluss der Antwort werden Nachspanne zurückgegeben.Trailers are returned after the response is complete. Daher müssen Sie auf alle Antwortnachrichten warten, bevor Sie auf die Nachspanne zugreifen.Therefore, you must await all response messages before accessing the trailers.

Unäre und Clientstreamingaufrufe müssen auf ResponseAsync warten, bevor sie GetTrailers() aufrufen können:Unary and client streaming calls must await ResponseAsync before calling GetTrailers():

var client = new Greet.GreeterClient(channel);
using var call = client.SayHelloAsync(new HelloRequest { Name = "World" });
var response = await call.ResponseAsync;

Console.WriteLine("Greeting: " + response.Message);
// Greeting: Hello World

var trailers = call.GetTrailers();
var myValue = trailers.GetValue("my-trailer-name");

Server- und bidirektionale Streamingaufrufe müssen zuerst vollständig den Antwortdatenstrom abwarten, bevor sie GetTrailers() aufrufen können:Server and bidirectional streaming calls must finish awaiting the response stream before calling GetTrailers():

var client = new Greet.GreeterClient(channel);
using var call = client.SayHellos(new HelloRequest { Name = "World" });

await foreach (var response in call.ResponseStream.ReadAllAsync())
{
    Console.WriteLine("Greeting: " + response.Message);
    // "Greeting: Hello World" is written multiple times
}

var trailers = call.GetTrailers();
var myValue = trailers.GetValue("my-trailer-name");

Auf Nachspanne kann auch über RpcException zugegriffen werden.Trailers are also accessible from RpcException. Ein Dienst kann Nachspanne eventuell zusammen mit einem gRPC-Status von „nicht in Ordnung“ zurückgeben.A service may return trailers together with a non-OK gRPC status. In dieser Situation werden die Nachspanne vom gRPC-Client aus der ausgelösten Ausnahme abgerufen:In this situation, the trailers are retrieved from the exception thrown by the gRPC client:

var client = new Greet.GreeterClient(channel);
string myValue = null;

try
{
    using var call = client.SayHelloAsync(new HelloRequest { Name = "World" });
    var response = await call.ResponseAsync;

    Console.WriteLine("Greeting: " + response.Message);
    // Greeting: Hello World

    var trailers = call.GetTrailers();
    myValue = trailers.GetValue("my-trailer-name");
}
catch (RpcException ex)
{
    var trailers = ex.Trailers;
    myValue = trailers.GetValue("my-trailer-name");
}

Konfigurieren von FristenConfigure deadline

Das Konfigurieren einer gRPC-Aufruffrist wird empfohlen, da sie eine Obergrenze für den Zeitraum vorgibt, in dem ein Aufruf ausgeführt werden kann.Configuring a gRPC call deadline is recommended because it provides an upper limit on how long a call can run for. Dadurch wird verhindert, dass fehlerhafte Dienste unbegrenzt lange ausgeführt werden und die Serverressourcen belasten.It stops misbehaving services from running forever and exhausting server resources. Fristen stellen einen wichtigen Aspekt bei der Erstellung zuverlässiger Apps dar.Deadlines are a useful tool for building reliable apps.

Konfigurieren Sie CallOptions.Deadline, um eine Frist für einen gRPC-Aufruf festzulegen:Configure CallOptions.Deadline to set a deadline for a gRPC call:

var client = new Greet.GreeterClient(channel);

try
{
    var response = await client.SayHelloAsync(
        new HelloRequest { Name = "World" },
        deadline: DateTime.UtcNow.AddSeconds(5));
    
    // Greeting: Hello World
    Console.WriteLine("Greeting: " + response.Message);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.DeadlineExceeded)
{
    Console.WriteLine("Greeting timeout.");
}

Weitere Informationen finden Sie unter Zuverlässige gRPC-Dienste mit Fristen und Abbrüchen.For more information, see Zuverlässige gRPC-Dienste mit Fristen und Abbrüchen.

Zusätzliche RessourcenAdditional resources