Aracılığıyla paylaş


.NET istemcisiyle gRPC hizmetlerini çağırma

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Uyarı

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Grpc.Net.Client NuGet paketinde bir .NET gRPC istemci kitaplığı bulunur. Bu belgede aşağıdakilerin nasıl yapılacağını açıklanmaktadır:

  • gRPC hizmetlerini çağırmak için bir gRPC istemcisi yapılandırın.
  • Tekli, sunucu akışlı, istemci akışlı ve çift yönlü akış yöntemlerine gRPC çağrıları yapın.

gRPC istemciyi yapılandırma

gRPC istemcileri, .proto dosyalarından oluşturulan somut istemci türleridir. Somut gRPC istemcisi, .proto dosyasındaki gRPC hizmetine karşılık gelen yöntemlere sahiptir. Örneğin, adlı Greeter bir hizmet, hizmeti çağırma yöntemlerini içeren bir GreeterClient tür oluşturur.

Bir kanaldan gRPC istemcisi oluşturulur. Bir kanal oluşturmak için kullanarak GrpcChannel.ForAddress başlayın ve ardından gRPC istemcisi oluşturmak için kanalı kullanın:

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

Kanal, gRPC hizmetine uzun süreli bir bağlantıyı temsil eder. Kanal oluşturulduğunda, hizmet çağırmayla ilgili seçeneklerle yapılandırılır. Örneğin, çağrı yapmak için kullanılan HttpClient, ileti gönderme ve alma boyutu üst sınırı ve günlük kaydı GrpcChannelOptions üzerinde belirtilebilir ve GrpcChannel.ForAddress ile kullanılabilir. Seçeneklerin tam listesi için bkz . istemci yapılandırma seçenekleri.

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’yi yapılandırma

gRPC istemcisi, çağrılan hizmetle aynı bağlantı düzeyi güvenliğini kullanmalıdır. gRPC istemcisi Aktarım Katmanı Güvenliği (TLS), gRPC kanalı oluşturulduğunda yapılandırılır. Bir gRPC istemcisi bir hizmeti çağırdığında bir hata oluşturur ve kanalın ve hizmetin bağlantı düzeyi güvenliği eşleşmiyor.

GRPC kanalını TLS kullanacak şekilde yapılandırmak için sunucu adresinin ile httpsbaşladığından emin olun. Örneğin, GrpcChannel.ForAddress("https://localhost:5001") HTTPS protokollerini kullanır. gRPC kanalı, TLS tarafından güvenli bir bağlantıyı otomatik olarak belirler ve gRPC çağrıları yapmak için güvenli bir bağlantı kullanır.

İpucu

gRPC, TLS üzerinden istemci sertifikası kimlik doğrulamayı destekler. İstemci sertifikalarını gRPC kanalıyla yapılandırma hakkında bilgi için bkz . ASP.NET Core için gRPC'de kimlik doğrulaması ve yetkilendirme.

Güvenli olmayan gRPC hizmetlerini çağırmak için sunucu adresinin ile httpbaşladığından emin olun. Örneğin, GrpcChannel.ForAddress("http://localhost:5000") HTTP protokollerini kullanır. .NET Core 3.1'de, .NET istemcisiyle güvenli olmayan gRPC hizmetlerini çağırmak için ek yapılandırma gerekir.

İstemci performansı

Kanal ve istemci performansı ve kullanımı:

  • Kanal oluşturmak pahalı bir işlem olabilir. gRPC çağrıları için bir kanalı yeniden kullanarak performans avantajları elde edebilirsiniz.
  • Kanal, sunucu bağlantılarını yönetir. Bağlantı kapatılır veya kaybolursa, bir sonraki gRPC çağrısı yapıldığında kanal otomatik olarak yeniden bağlanır.
  • gRPC istemcileri kanallarla oluşturulur. gRPC istemcileri basit nesnelerdir ve önbelleğe alınması veya yeniden kullanılması gerekmez.
  • Farklı istemci türleri dahil olmak üzere bir kanaldan birden çok gRPC istemcisi oluşturulabilir.
  • Kanaldan oluşturulan bir kanal ve istemciler birden çok iş parçacığı tarafından güvenle kullanılabilir.
  • Kanaldan oluşturulan istemciler birden çok eşzamanlı arama yapabilir.

GrpcChannel.ForAddress gRPC istemcisi oluşturmak için tek seçenek değildir. bir ASP.NET Core uygulamasından gRPC hizmetlerini çağırıyorsanız gRPC istemci fabrikası tümleştirmesini göz önünde bulundurun. ile HttpClientFactory gRPC tümleştirmesi, gRPC istemcileri oluşturmaya merkezi bir alternatif sunar.

gRPC yöntemlerini çağırırken, zaman uyumsuz ile zaman uyumsuz programlama kullanmayı tercih edin vebekleyin. Task.Result veya Task.Wait()gibi bloklama yöntemleri kullanarak gRPC çağrıları yapmak, diğer görevlerin bir iş parçacığını kullanmasını önler. Bu, iş parçacığı havuzunun tükenmesi ve düşük performansa neden olabilir. Bu, uygulamanın bir kilitlenmeyle donmasına neden olabilir. Daha fazla bilgi için bkz. istemci uygulamalarında zaman uyumsuz çağrılar.

gRPC çağrıları yapma

gRPC çağrısı, istemcide bir yöntem çağrılarak başlatılır. gRPC istemcisi, ileti serileştirmeyi işler ve gRPC çağrısını doğru hizmete yönlendirir.

gRPC'nin farklı yöntem türleri vardır. Bir gRPC çağrısı yapmak için istemcinin nasıl kullanıldığı, çağrılan yöntemin türüne bağlıdır. gRPC yöntem türleri şunlardır:

  • Tekil
  • Sunucudan akış
  • İstemci akışı
  • çift yönlü akış

Tekli arama

Üniter bir çağrı, istemcinin istek iletisi göndermesiyle başlar. Hizmet tamamlandığında bir yanıt iletisi döndürülür.

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

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

.proto dosyasındaki her bir tekli hizmet yöntemi, somut gRPC istemci türünde, yöntemi çağırmak için iki .NET yöntemiyle sonuçlanır: biri zaman uyumsuz bir yöntem, diğeri ise engelleme yöntemi. Örneğin, GreeterClient üzerinde SayHello çağırmanın iki yolu vardır:

  • GreeterClient.SayHelloAsync - Greeter.SayHello hizmetini asenkron olarak çağırır. Beklenebilir.
  • GreeterClient.SayHello - Greeter.SayHello hizmetini çağırır ve tamamlanana kadar bloke eder. Zaman uyumsuz kodda kullanmayın. Performans ve güvenilirlik sorunlarına neden olabilir.

Daha fazla bilgi için bkz. istemci uygulamalarında zaman uyumsuz çağrılar.

Sunucu akış çağrısı

Sunucu akış çağrısı, istemcinin istek iletisi göndermesiyle başlar. ResponseStream.MoveNext() hizmetten canlı yayımlanan iletileri okur. ResponseStream.MoveNext() false'i döndürdüğünde, sunucu akış çağrısı tamamlanır.

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 veya üzerini kullanırken, await foreach söz dizimi iletileri okumak için kullanılabilir. IAsyncStreamReader<T>.ReadAllAsync() Uzantı yöntemi, yanıt akışındaki tüm iletileri okur:

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
}

Sunucu akış çağrısı başlatıldığında döndürülen tür IDisposable uygular. Durdurulmasını ve tüm kaynakların temizlendiğinden emin olmak için her zaman bir akış çağrısı atın.

İstemci akış çağrısı

İstemci akış çağrısı, istemci ileti göndermeden başlar. Müşteri, RequestStream.WriteAsync ile mesaj göndermeyi seçebilir. İstemci ileti göndermeyi bitirdiğinde, RequestStream.CompleteAsync() hizmete bildirmek için çağrılmalıdır. Hizmet bir yanıt iletisi döndürdüğünde çağrı tamamlanır.

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

İstemci akış çağrısı başlatıldığında döndürülen tür IDisposable uygular. Durdurulmasını ve tüm kaynakların temizlendiğinden emin olmak için her zaman bir akış çağrısı atın.

çift yönlü akış çağrısı

çift yönlü akış çağrısı, istemci ileti göndermeden başlar. İstemci RequestStream.WriteAsync ile mesaj göndermeyi seçebilir. Hizmetten akışı yapılan iletilere ResponseStream.MoveNext() veya ResponseStream.ReadAllAsync() ile erişilebilir. Çift yönlü akış çağrısı, ResponseStream artık ileti göndermediğinde tamamlanır.

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;

En iyi performans için ve istemci ve hizmetteki gereksiz hataları önlemek için çift yönlü akış çağrılarını düzgün bir şekilde tamamlamayı deneyin. Sunucu istek akışını okumayı bitirdiğinde ve istemci yanıt akışını okumayı bitirdiğinde çift yönlü bir çağrı düzgün bir şekilde tamamlar. Yukarıdaki örnek çağrı, düzgün bir şekilde biten çift yönlü bir çağrı örneğidir. Çağrıda istemci:

  1. Yeni bir çift yönlü akış çağrısını, EchoClient.Echo çağrısı yaparak başlatır.
  2. kullanarak ResponseStream.ReadAllAsync()hizmetten gelen iletileri okumak için bir arka plan görevi oluşturur.
  3. ile RequestStream.WriteAsyncsunucuya ileti gönderir.
  4. ile RequestStream.CompleteAsync()ileti göndermeyi bitirdiğini sunucuya bildirir.
  5. Arka plan görevi tüm gelen iletileri okuyana kadar bekler.

çift yönlü akış çağrısı sırasında, istemci ve hizmet istedikleri zaman birbirlerine ileti gönderebilir. İki yönlü bir çağrıyla etkileşim için en iyi istemci mantığı, hizmet mantığına bağlı olarak değişir.

Çift yönlü akış çağrısının başlatılmasıyla döndürülen tür, IDisposable'yi uygular. Her zaman bir akış çağrısını sonlandırın veya yok edin, böylece durdurulduğundan ve tüm kaynakların temizlendiğinden emin olun.

gRPC üst bilgilerine eriş

gRPC çağrıları yanıt üst bilgilerini döndürür. HTTP yanıt üst bilgileri, döndürülen iletiyle ilgili olmayan bir çağrıyla ilgili ad/değer meta verilerini geçirir.

Başlıklara, bir meta veri koleksiyonu döndüren ResponseHeadersAsync kullanılarak erişilebilir. Üst bilgiler genellikle yanıt iletisiyle döndürülür; Bu nedenle, onları beklemelisiniz.

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 Kullanım:

  • Üst bilgi koleksiyonunu almak için ResponseHeadersAsync sonucunu beklemelisiniz.
  • ResponseAsync'ye (veya akış sırasında yanıt akışına) daha önce erişilmesi gerekmez. Bir yanıt döndürüldüyse, ResponseHeadersAsync anında üst bilgileri döndürür.
  • Bağlantı hatası veya sunucu hatası varsa ve gRPC çağrısı için üst bilgiler döndürülmezse bir istisna fırlatır.

Access gRPC fragmanları

gRPC çağrıları yanıt fragmanlarını döndürebilir. Çağrı hakkında ad/değer meta verileri sağlamak için römorklar kullanılır. Trailer'lar, HTTP üst bilgilerine benzer işlevsellik sağlar, ancak çağrının sonunda alınır.

Fragmanlara, GetTrailers() kullanılarak erişilebilir ve bu da bir meta veri koleksiyonu döndürür. Römorklar yanıt tamamen tamamlandıktan sonra geri döndürülür. Bu nedenle, fragmanlara erişmeden önce tüm yanıt iletilerini beklemeniz gerekir.

Çağrılmadan önce ResponseAsync tek yönlü ve istemci akış çağrıları beklemelidir 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");

Sunucu ve çift yönlü akış çağrılarının, GetTrailers() çağrılmadan önce yanıt akışını beklemeyi bitirmesi gerekir.

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

Römorklar RpcExceptiondan da erişilebilir. Bir hizmet, geçerli olmayan bir gRPC durumuyla birlikte treyleri döndürebilir. Bu durumda, fragmanlar gRPC istemcisi tarafından oluşturulan özel durumdan alınır:

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

Son teslim tarihini yapılandırma

Bir aramanın ne kadar süreyle çalışabileceğine ilişkin bir üst sınır sağladığından gRPC arama son tarihini yapılandırmanız önerilir. Hatalı davranan hizmetlerin sonsuza kadar çalışmasını ve sunucu kaynaklarının tükenmesini engeller. Son tarihler, güvenilir uygulamalar oluşturmak için kullanışlı bir araçtır.

CallOptions.Deadline'yi bir gRPC çağrısı için son tarih belirlemek üzere yapılandırın.

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

Daha fazla bilgi için bkz. Son tarihler ve iptal özelliklerine sahip güvenilir gRPC hizmetleri.

Ek kaynaklar