Memanggil layanan gRPC dengan klien .NET

Pustaka klien .NET gRPC tersedia di paket Grpc.Net.Client NuGet. Dokumen ini menjelaskan cara:

  • Konfigurasikan klien gRPC untuk memanggil layanan gRPC.
  • Lakukan panggilan gRPC ke metode streaming unary, server, streaming klien, dan streaming dua arah.

Mengonfigurasi klien gRPC

Klien gRPC adalah jenis klien konkret yang dihasilkan dari file .proto. Klien gRPC konkret memiliki metode yang diterjemahkan ke layanan gRPC dalam file .proto. Misalnya, layanan yang disebut Greeter menghasilkan GreeterClient jenis dengan metode untuk memanggil layanan.

Klien gRPC dibuat dari saluran. Mulailah dengan menggunakan GrpcChannel.ForAddress untuk membuat saluran, lalu gunakan saluran untuk membuat klien gRPC:

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

Saluran mewakili koneksi berumur panjang ke layanan gRPC. Saat saluran dibuat, saluran dikonfigurasi dengan opsi yang terkait dengan panggilan layanan. Misalnya, yang HttpClient digunakan untuk melakukan panggilan, ukuran pesan kirim dan terima maksimum, dan pengelogan dapat ditentukan pada GrpcChannelOptions dan digunakan dengan GrpcChannel.ForAddress. Untuk daftar lengkap opsi, lihat opsi konfigurasi klien.

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

Konfigurasikan TLS

Klien gRPC harus menggunakan keamanan tingkat koneksi yang sama dengan layanan yang disebut. Keamanan Lapisan Transportasi (TLS) klien gRPC dikonfigurasi saat saluran gRPC dibuat. Klien gRPC melemparkan kesalahan saat memanggil layanan dan keamanan tingkat koneksi saluran dan layanan tidak cocok.

Untuk mengonfigurasi saluran gRPC untuk menggunakan TLS, pastikan alamat server dimulai dengan https. Misalnya, GrpcChannel.ForAddress("https://localhost:5001") menggunakan protokol HTTPS. Saluran gRPC secara otomatis menegosiasikan koneksi yang diamankan oleh TLS dan menggunakan koneksi aman untuk melakukan panggilan gRPC.

Tip

gRPC mendukung autentikasi sertifikat klien melalui TLS. Untuk informasi tentang mengonfigurasi sertifikat klien dengan saluran gRPC, lihat Autentikasi dan otorisasi di gRPC untuk ASP.NET Core.

Untuk memanggil layanan gRPC yang tidak aman, pastikan alamat server dimulai dengan http. Misalnya, GrpcChannel.ForAddress("http://localhost:5000") menggunakan protokol HTTP. Di .NET Core 3.1, konfigurasi tambahan diperlukan untuk memanggil layanan gRPC yang tidak aman dengan klien .NET.

Performa klien

Performa dan penggunaan saluran dan klien:

  • Membuat saluran bisa menjadi operasi yang mahal. Menggunakan kembali saluran untuk panggilan gRPC memberikan manfaat performa.
  • Saluran mengelola koneksi ke server. Jika koneksi ditutup atau hilang, saluran secara otomatis tersambung kembali saat panggilan gRPC dilakukan.
  • Klien gRPC dibuat dengan saluran. Klien gRPC adalah objek ringan dan tidak perlu di-cache atau digunakan kembali.
  • Beberapa klien gRPC dapat dibuat dari saluran, termasuk berbagai jenis klien.
  • Saluran dan klien yang dibuat dari saluran dapat digunakan dengan aman oleh beberapa utas.
  • Klien yang dibuat dari saluran dapat melakukan beberapa panggilan simultan.

GrpcChannel.ForAddress bukan satu-satunya opsi untuk membuat klien gRPC. Jika memanggil layanan gRPC dari aplikasi ASP.NET Core, pertimbangkan integrasi pabrik klien gRPC. Integrasi gRPC dengan HttpClientFactory menawarkan alternatif terpusat untuk membuat klien gRPC.

Catatan

Memanggil gRPC melalui HTTP/2 dengan Grpc.Net.Client saat ini tidak didukung di Xamarin. Kami berupaya meningkatkan dukungan HTTP/2 dalam rilis Xamarin di masa mendatang. Grpc.Core dan gRPC-Web adalah alternatif yang layak yang berfungsi saat ini.

Melakukan panggilan gRPC

Panggilan gRPC dimulai dengan memanggil metode pada klien. Klien gRPC akan menangani serialisasi pesan dan menangani panggilan gRPC ke layanan yang benar.

gRPC memiliki berbagai jenis metode. Bagaimana klien digunakan untuk melakukan panggilan gRPC tergantung pada jenis metode yang disebut. Jenis metode gRPC adalah:

  • Unary
  • Streaming server
  • Streaming klien
  • Streaming dua arah

Panggilan tidak sah

Panggilan tidak sah dimulai dengan klien yang mengirim pesan permintaan. Pesan respons dikembalikan saat layanan selesai.

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

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

Setiap metode layanan unary dalam .proto file akan menghasilkan dua metode .NET pada jenis klien gRPC konkret untuk memanggil metode : metode asinkron dan metode pemblokiran. Misalnya, pada GreeterClient ada dua cara untuk memanggil SayHello:

  • GreeterClient.SayHelloAsync - memanggil Greeter.SayHello layanan secara asinkron. Bisa ditunggu.
  • GreeterClient.SayHello - memanggil Greeter.SayHello layanan dan memblokir sampai selesai. Jangan gunakan dalam kode asinkron.

Panggilan streaming server

Panggilan streaming server dimulai dengan klien mengirim pesan permintaan. ResponseStream.MoveNext() membaca pesan yang dialirkan dari layanan. Panggilan streaming server selesai saat ResponseStream.MoveNext() mengembalikan 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
}

Saat menggunakan C# 8 atau yang await foreach lebih baru, sintaks dapat digunakan untuk membaca pesan. Metode IAsyncStreamReader<T>.ReadAllAsync() ekstensi membaca semua pesan dari aliran respons:

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
}

Panggilan streaming klien

Panggilan streaming klien dimulai tanpa klien mengirim pesan. Klien dapat memilih untuk mengirim pesan dengan RequestStream.WriteAsync. Ketika klien telah selesai mengirim pesan, RequestStream.CompleteAsync() harus dipanggil untuk memberi tahu layanan. Panggilan selesai ketika layanan mengembalikan pesan respons.

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

Panggilan streaming dua arah

Panggilan streaming dua arah dimulai tanpa klien mengirim pesan. Klien dapat memilih untuk mengirim pesan dengan RequestStream.WriteAsync. Pesan yang dialirkan dari layanan dapat diakses dengan ResponseStream.MoveNext() atau ResponseStream.ReadAllAsync(). Panggilan streaming dua arah selesai ketika ResponseStream tidak memiliki pesan lagi.

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;

Untuk performa terbaik, dan untuk menghindari kesalahan yang tidak perlu dalam klien dan layanan, cobalah untuk menyelesaikan panggilan streaming dua arah dengan anggun. Panggilan dua arah selesai dengan baik ketika server telah selesai membaca aliran permintaan dan klien telah selesai membaca aliran respons. Panggilan sampel sebelumnya adalah salah satu contoh panggilan dua arah yang berakhir dengan baik. Dalam panggilan, klien:

  1. Memulai panggilan streaming dua arah baru dengan memanggil EchoClient.Echo.
  2. Membuat tugas latar belakang untuk membaca pesan dari layanan menggunakan ResponseStream.ReadAllAsync().
  3. Mengirim pesan ke server dengan RequestStream.WriteAsync.
  4. Memberi tahu server bahwa server telah selesai mengirim pesan dengan RequestStream.CompleteAsync().
  5. Tunggu hingga tugas latar belakang membaca semua pesan masuk.

Selama panggilan streaming dua arah, klien dan layanan dapat mengirim pesan satu sama lain kapan saja. Logika klien terbaik untuk berinteraksi dengan panggilan dua arah bervariasi tergantung pada logika layanan.

Mengakses header gRPC

Panggilan gRPC mengembalikan header respons. Header respons HTTP meneruskan metadata nama/nilai tentang panggilan yang tidak terkait dengan pesan yang dikembalikan.

Header dapat diakses menggunakan ResponseHeadersAsync, yang mengembalikan kumpulan metadata. Header biasanya dikembalikan dengan pesan respons; Oleh karena itu, Anda harus menunggu mereka.

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 Penggunaan:

  • Harus menunggu hasil ResponseHeadersAsync untuk mendapatkan koleksi header.
  • Tidak harus diakses sebelumnya ResponseAsync (atau aliran respons saat streaming). Jika respons telah dikembalikan, maka ResponseHeadersAsync mengembalikan header secara instan.
  • Akan melemparkan pengecualian jika ada kesalahan koneksi atau server dan header tidak dikembalikan untuk panggilan gRPC.

Mengakses trailer gRPC

Panggilan gRPC dapat mengembalikan trailer respons. Trailer digunakan untuk memberikan metadata nama/nilai tentang panggilan. Trailer menyediakan fungsionalitas serupa dengan header HTTP, tetapi diterima di akhir panggilan.

Trailer dapat diakses menggunakan GetTrailers(), yang mengembalikan kumpulan metadata. Trailer dikembalikan setelah respons selesai. Oleh karena itu, Anda harus menunggu semua pesan respons sebelum mengakses trailer.

Panggilan streaming unary dan klien harus menunggu ResponseAsync sebelum memanggil 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");

Panggilan streaming server dan dua arah harus selesai menunggu aliran respons sebelum memanggil 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");

Trailer juga dapat diakses dari RpcException. Layanan dapat mengembalikan trailer bersama dengan status gRPC non-OK. Dalam situasi ini, trailer diambil dari pengecualian yang dilemparkan oleh klien gRPC:

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

Mengonfigurasi tenggat waktu

Mengonfigurasi tenggat waktu panggilan gRPC disarankan karena memberikan batas atas berapa lama panggilan dapat berjalan. Ini menghentikan layanan yang salah tingkah laku agar tidak berjalan selamanya dan menghabiskan sumber daya server. Tenggat waktu adalah alat yang berguna untuk membangun aplikasi yang andal.

Konfigurasikan CallOptions.Deadline untuk mengatur tenggat waktu untuk panggilan gRPC:

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

Untuk informasi selengkapnya, lihat Layanan gRPC andal dengan tenggat waktu dan pembatalan.

Sumber daya tambahan