Bagikan melalui


Memanggil layanan gRPC dengan klien .NET

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.

Peringatan

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.

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 jenis GreeterClient dengan metode untuk memanggil layanan tersebut.

Klien gRPC dibangun dari sebuah 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 menimbulkan kesalahan ketika memanggil layanan dan keamanan pada tingkat koneksi saluran dan layanan tidak sesuai.

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.

Kinerja pelanggan

Performa dan penggunaan saluran dan klien:

  • Membuat saluran bisa menjadi operasi yang mahal. Menggunakan kembali kanal untuk panggilan gRPC memberikan keuntungan kinerja.
  • Saluran mengelola koneksi ke server. Jika koneksi ditutup atau hilang, saluran secara otomatis tersambung kembali saat panggilan gRPC dilakukan.
  • Aplikasi 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 yang sama, 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.

Saat memanggil metode gRPC, lebih suka menggunakan pemrograman asinkron dengan asinkron dan menunggu. Melakukan panggilan gRPC yang bersifat memblokir, seperti menggunakan Task.Result atau Task.Wait(), mencegah penggunaan utas oleh tugas lain. Hal ini dapat menyebabkan kelelahan sumber daya kumpulan utas dan performa yang buruk. Hal ini dapat menyebabkan aplikasi menggantung karena kebuntuan. Untuk informasi selengkapnya, lihat Panggilan asinkron di aplikasi klien.

Melakukan panggilan pada 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 oleh server
  • Streaming untuk klien
  • Streaming dua arah

Panggilan unary

Panggilan unary 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 layanan Greeter.SayHello secara asinkron. Bisa ditunggu.
  • GreeterClient.SayHello - memanggil layanan Greeter.SayHello dan memblokir hingga selesai. Jangan gunakan dalam kode asinkron. Dapat menyebabkan masalah performa dan keandalan.

Untuk informasi selengkapnya, lihat Panggilan asinkron di aplikasi klien.

Panggilan server streaming

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 versi yang lebih baru, sintaks await foreach 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
}

Jenis yang dikembalikan saat memulai panggilan streaming server mengimplementasikan IDisposable. Selalu buang panggilan streaming untuk memastikan panggilan dihentikan dan semua sumber daya dibersihkan.

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

Jenis yang dikembalikan dari memulai panggilan streaming klien mengimplementasikan IDisposable. Selalu buang panggilan streaming untuk memastikan panggilan dihentikan dan semua sumber daya dibersihkan.

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.

Jenis yang dikembalikan dari memulai panggilan streaming dua arah mengimplementasikan IDisposable. Selalu buang panggilan streaming untuk memastikan panggilan dihentikan dan semua sumber daya dibersihkan.

Mengakses header gRPC

Panggilan gRPC mengembalikan header tanggapan. 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 kumpulan header.
  • Tidak harus diakses sebelum ResponseAsync (atau aliran respons saat melakukan streaming). Jika respons telah dikembalikan, maka ResponseHeadersAsync mengembalikan header secara instan.
  • Akan menimbulkan pengecualian jika terdapat kesalahan pada koneksi atau server dan header tidak disertakan dalam panggilan gRPC.

Mengakses trailer gRPC

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

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

Panggilan unary dan streaming 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 berperilaku buruk dari 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: