Megosztás a következőn keresztül:


GRPC-szolgáltatások meghívása a .NET-ügyféllel

Jegyzet

Ez nem a cikk legújabb verziója. A jelenlegi kiadásért lásd ennek a cikknek a .NET 9-es verzióját.

Figyelmeztetés

A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. Az aktuális kiadáshoz lásd ennek a cikknek a .NET 9-es verzióját.

Fontos

Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.

Az aktuális kiadást lásd a cikk .NET 9-es verzióját.

A .NET gRPC-ügyfélkódtár a Grpc.Net.Client NuGet-csomagban érhető el. Ez a dokumentum a következő lépéseket ismerteti:

  • GRPC-ügyfél konfigurálása gRPC-szolgáltatások meghívásához.
  • GRPC-hívásokat kezdeményezhet a unary, a kiszolgálói streamelés, az ügyfélstreamelés és a kétirányú streamelési módszerek felé.

GRPC-ügyfél konfigurálása

A gRPC-ügyfelek konkrét kliens típusok, amelyek generálódnak .proto fájlokból. A konkrét gRPC-ügyfél olyan metódusokat tartalmaz, amelyek a .proto fájlban lévő gRPC szolgáltatásra fordítják le. Egy Greeter nevű szolgáltatás például létrehoz egy GreeterClient típust a szolgáltatás meghívására szolgáló metódusokkal.

A gRPC-kliens csatornából jön létre. Először a GrpcChannel.ForAddress használatával hozzon létre egy csatornát, majd a csatornával hozzon létre egy gRPC-ügyfelet:

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

A csatorna egy gRPC szolgáltatás hosszú élettartamú kapcsolatát jelenti. Amikor létrejön egy csatorna, a szolgáltatás hívásához kapcsolódó beállítások vannak konfigurálva. A például hívások lebonyolítására használt HttpClient, az üzenetek küldésének és fogadásának maximális mérete, valamint a naplózás megadható a GrpcChannelOptions-en, és használható a GrpcChannel.ForAddress-vel. A beállítások teljes listáját ügyfélkonfigurációs beállításokcímű cikkben találja.

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

TLS konfigurálása

A gRPC-ügyfélnek ugyanazt a kapcsolatszintű biztonságot kell használnia, mint a hívott szolgáltatásnak. A gRPC-ügyfél átviteli rétegének biztonsága (TLS) a gRPC-csatorna létrehozásakor van konfigurálva. A gRPC-ügyfél hibát jelez, amikor egy szolgáltatást hív meg, és a csatorna és a szolgáltatás kapcsolatszintű biztonsága nem egyezik.

Ha gRPC-csatornát szeretne konfigurálni a TLS használatára, győződjön meg arról, hogy a kiszolgáló címe httpskezdődik. Például GrpcChannel.ForAddress("https://localhost:5001") HTTPS protokollt használ. A gRPC-csatorna automatikusan egyeztet egy TLS által védett kapcsolatot, és biztonságos kapcsolatot használ a gRPC-hívások indításához.

Borravaló

A gRPC támogatja az ügyféltanúsítványok TLS-en keresztüli hitelesítését. További információ az ügyféltanúsítványok gRPC-csatornával való konfigurálásáról: Hitelesítés és engedélyezés a gRPC-ben ASP.NET Core.

A nem biztonságos gRPC-szolgáltatások meghívásához győződjön meg arról, hogy a kiszolgáló címe httpkezdődik. Például GrpcChannel.ForAddress("http://localhost:5000") HTTP protokollt használ. A .NET Core 3.1-ben további konfigurációra van szükség a .NET-ügyféllel nem biztonságos gRPC-szolgáltatásokhívásához.

Ügyfélteljesítmény

Csatorna- és ügyfélteljesítmény és -használat:

  • A csatorna létrehozása költséges művelet lehet. A gRPC-hívások csatornáinak újrafelhasználása teljesítménybeli előnyöket biztosít.
  • A csatorna kezeli a kiszolgálóval létesített kapcsolatokat. Ha a kapcsolat megszakad vagy elveszik, a csatorna automatikusan újracsatlakozik, amikor legközelebb egy gRPC-hívást kezdeményeznek.
  • A gRPC-ügyfeleket csatornák segítségével hozzák létre. A gRPC kliensek könnyű objektumok, és nincs szükség gyorsítótárazásra vagy újrafelhasználásra.
  • Egy csatornáról több gRPC-ügyfél is létrehozható, beleértve a különböző típusú ügyfeleket is.
  • Egy csatorna és az abból létrehozott ügyfelek több szál által is biztonságosan használhatók.
  • A csatornáról létrehozott ügyfelek több egyidejű hívást is kezdeményezhetnek.

nem GrpcChannel.ForAddress az egyetlen lehetőség a gRPC-ügyfél létrehozásához. Ha gRPC-szolgáltatásokat hív meg egy ASP.NET Core-alkalmazásból, fontolja meg gRPC-ügyfél-előállító integrációját. A gRPC HttpClientFactory integrációja központi alternatívát kínál a gRPC-ügyfelek létrehozásához.

GRPC-metódusok hívásakor inkább aszinkron programozást használjon aszinkronnal, és várja meg. Ha gRPC-hívásokat kezdeményez blokkolással, például Task.Result vagy Task.Wait()használatával, megakadályozza, hogy más feladatok használják a szálakat. Ez a szálkészlet éhezéséhez és gyenge teljesítményhez vezethet. Ez okozhatja, hogy az alkalmazás holtponttal lóg. További információ: Aszinkron hívások az ügyfélalkalmazásokban.

GRPC-hívások indítása

A gRPC-hívás egy metódus meghívásával indítható el az ügyfélen. A gRPC-ügyfél kezeli az üzenetek szerializálását és a gRPC-hívás megfelelő szolgáltatáshoz való kezelését.

A gRPC különböző típusú metódusokkal rendelkezik. A kliens gRPC-híváshoz való használata a hívott metódus típusától függ. A gRPC metódustípusok a következők:

  • Unáris
  • Kiszolgálóalapú streamelés
  • Ügyfél általi adatátvitel
  • Kétirányú streamelés

Unary hívás

Egy unary hívás azzal kezdődik, hogy az ügyfél kérésüzenetet küld. A szolgáltatás befejeződésekor a rendszer válaszüzenetet ad vissza.

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

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

A .proto fájlban lévő egyes unary service metódusok két .NET-metódust eredményeznek a konkrét gRPC-ügyféltípuson a metódus meghívásához: egy aszinkron metódust és egy blokkoló metódust. Például az GreeterClient esetében kétféleképpen lehet hívni a SayHello-et.

  • GreeterClient.SayHelloAsync – a Greeter.SayHello szolgáltatást aszinkron módon hívja meg. Megvárható.
  • GreeterClient.SayHello – meghívja a Greeter.SayHello szolgáltatást, és blokkolja a folyamatot a befejezésig. Ne használja aszinkron kódban. Teljesítmény- és megbízhatósági problémákat okozhat.

További információ: Aszinkron hívások az ügyfélalkalmazásokban.

Kiszolgáló streamelési hívása

A kiszolgáló streamelési hívása azzal kezdődik, hogy az ügyfél kérésüzenetet küld. ResponseStream.MoveNext() felolvassa a szolgáltatásból streamelt üzeneteket. A kiszolgáló streamelési hívása akkor fejeződik be, amikor ResponseStream.MoveNext()falsead vissza.

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
}

C# 8 vagy újabb használata esetén a await foreach szintaxis használható üzenetek olvasására. A IAsyncStreamReader<T>.ReadAllAsync() bővítménymetódus beolvassa a válaszfolyam összes üzenetét:

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
}

Amikor egy kiszolgáló streaming hívását elindítják, az ekkor visszaadott típus implementálja a IDisposable. Mindig szüntessen meg egy streaming hívást annak biztosítására, hogy leálljon, és az összes erőforrás fel legyen szabadítva.

Ügyfél által közvetített hívás

Az ügyfél által streamelt hívás anélkül kezdődik, hogy az ügyfél üzenetet küldene. Az ügyfél dönthet úgy, hogy üzeneteket küld a RequestStream.WriteAsync-nal. Ha az ügyfél befejezte az üzenetek küldését, RequestStream.CompleteAsync() kell meghívni, hogy értesítse a szolgáltatást. A hívás akkor fejeződik be, amikor a szolgáltatás válaszüzenetet ad vissza.

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

A kliensoldali streamelési hívás indításakor visszaadott típus a IDisposable-t implementálja. Mindig zárjon le egy streaming hívást annak érdekében, hogy leálljon, és minden erőforrás fel legyen szabadítva.

Kétirányú streamelési hívás

Kétirányú streamelési hívás indul el anélkül, hogy az ügyfél üzenetet küldene. Az ügyfél dönthet úgy, hogy üzeneteket küld a RequestStream.WriteAsync-nal. A szolgáltatásból streamelt üzenetek ResponseStream.MoveNext() vagy ResponseStream.ReadAllAsync()érhetők el. A kétirányú streamelési hívás akkor fejeződik be, ha a ResponseStream nem tartalmaz több üzenetet.

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;

A legjobb teljesítmény érdekében, valamint az ügyfél és szolgáltatás szükségtelen hibáinak elkerülése érdekében próbálja meg elegánsan végrehajtani a kétirányú streamelési hívásokat. A kétirányú hívás akkor fejeződik be kecsesen, ha a kiszolgáló befejezte a kérésfolyam olvasását, és az ügyfél befejezte a válaszfolyam olvasását. Az előző mintahívás egy olyan kétirányú hívás példája, amely kecsesen végződik. A hívásban az ügyfél:

  1. Új kétirányú streamhívás indítása EchoClient.Echomeghívásával.
  2. Létrehoz egy háttérfeladatot, amely üzeneteket olvas be a szolgáltatásból a ResponseStream.ReadAllAsync()használatával.
  3. Üzeneteket küld a kiszolgálónak RequestStream.WriteAsync-val.
  4. Értesíti a kiszolgálót, hogy befejeződött az üzenetek küldése RequestStream.CompleteAsync().
  5. Megvárja, amíg a háttérfeladat beolvassa az összes bejövő üzenetet.

Kétirányú streamelési hívás során az ügyfél és a szolgáltatás bármikor küldhet üzeneteket egymásnak. A kétirányú hívásokkal való kommunikációhoz a legjobb ügyféllogika a szolgáltatáslogikától függően változik.

A kétirányú streamelési hívás elindítása után visszaadott típus implementálja IDisposable. Mindig szüntessen meg egy streaming hívást annak biztosítására, hogy leálljon, és az összes erőforrás fel legyen szabadítva.

gRPC-fejlécek elérése

gRPC-hívások válaszfejléceket ad vissza. A HTTP-válaszfejlécek név-/érték metaadatokat adnak át egy olyan hívásról, amely nem kapcsolódik a visszaadott üzenethez.

A fejlécek a ResponseHeadersAsynchasználatával érhetők el, amely metaadat-gyűjteményt ad vissza. A fejléceket általában a válaszüzenet adja vissza; ezért várnia kell rájuk.

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;

ResponseHeadersAsync használat:

  • A fejlécgyűjtemény lekéréséhez meg kell várnia a ResponseHeadersAsync eredményét.
  • Nem szükséges hozzáférni a ResponseAsync előtt (vagy a válaszfolyamhoz streameléskor). Ha válasz érkezett, akkor ResponseHeadersAsync azonnal visszaadja a fejléceket.
  • Kivételt okoz, ha kapcsolati vagy kiszolgálói hiba történt, és a gRPC-hívás fejlécei nem lettek visszaadva.

gRPC végmetaadatok elérése

Előfordulhat, hogy a gRPC-hívások visszaküldenek kiegészítő válasz adatokat. A pótkocsik a hívással kapcsolatos név-érték metaadatok megadására szolgálnak. Az utótagok hasonló funkciókat biztosítanak, mint a HTTP-fejlécek, de a hívás végén érkeznek.

Az előzetesek a GetTrailers()használatával érhetők el, amely visszaad egy metaadat-gyűjteményt. A pótkocsikat a válasz befejezése után adják vissza. Ezért az előzetesek elérése előtt minden válaszüzenetre várnia kell.

Az unary és ügyféloldali streamelési hívásoknak várniuk kell ResponseAsync-ra, mielőtt meghívják GetTrailers()-et.

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");

A kiszolgálói és kétirányú streamelési hívásoknak a válaszfolyamra várva kell befejeződniük, mielőtt meghívják 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");

A pótkocsik a RpcException-tól is elérhetők. A szolgáltatás az ok nélküli gRPC állapotú pótkocsikat is visszaküldheti. Ebben az esetben a gRPC kliens által dobott kivételből származó metaadatok kerülnek lekérésre.

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");
}

Határidő konfigurálása

A gRPC-hívás határidejének konfigurálása azért ajánlott, mert felső korlátot biztosít arra vonatkozóan, hogy mennyi ideig futhat egy hívás. Megakadályozza, hogy a helytelenül működő szolgáltatások örökké fussanak, és ezzel kimerítsék a kiszolgáló erőforrásait. A határidők hasznos eszközök a megbízható alkalmazások létrehozásához.

Konfigurálja a CallOptions.Deadline egy gRPC-hívás határidejének beállításához:

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.");
}

További információkért lásd: Megbízható gRPC-szolgáltatások határidőkkel és lemondási lehetőségekkel.

További erőforrások