.NET istemcisiyle gRPC hizmetlerini çağırma

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ışı, istemci akışı 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 çevrilen 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, HttpClient çağrı yapmak için kullanılan, ileti gönderme ve alma boyutu üst sınırı ve günlük kaydı üzerinde GrpcChannelOptions belirtilebilir ve ile GrpcChannel.ForAddresskullanı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.

Not

ile Grpc.Net.Client HTTP/2 üzerinden gRPC çağrısı şu anda Xamarin'de desteklenmiyor. Gelecekteki bir Xamarin sürümünde HTTP/2 desteğini geliştirmek için çalışıyoruz. Grpc.Core ve gRPC-Web , bugün çalışan uygulanabilir alternatiflerdir.

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. İstemcinin gRPC çağrısı yapmak için nasıl kullanıldığı, adlı yöntemin türüne bağlıdır. gRPC yöntem türleri şunlardır:

  • Birli
  • Sunucu akışı
  • İstemci akışı
  • çift yönlü akış

Birli arama

Birli arama, 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

Dosyadaki .proto her bir tekli hizmet yöntemi, yöntemini çağırmak için somut gRPC istemci türünde iki .NET yöntemiyle sonuçlanır: zaman uyumsuz bir yöntem ve bir engelleme yöntemi. Örneğin, öğesini GreeterClient çağırmanın SayHelloiki yolu vardır:

  • GreeterClient.SayHelloAsync - hizmeti zaman uyumsuz olarak çağırır Greeter.SayHello . Beklenebilir.
  • GreeterClient.SayHello - tamamlanana kadar hizmeti ve blokları çağırır Greeter.SayHello . Zaman uyumsuz kodda kullanmayın.

Sunucu akış çağrısı

Sunucu akış çağrısı, istemcinin istek iletisi göndermesiyle başlar. ResponseStream.MoveNext() hizmetten akışı yapılan iletileri okur. döndürdüğünde ResponseStream.MoveNext()falsesunucu 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
}

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

İstemci akış çağrısı, istemci ileti göndermeden başlar. İstemci ile RequestStream.WriteAsyncileti 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

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

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

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. çağrısı EchoClient.Echoyaparak yeni bir çift yönlü akış çağrısı 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.

Access gRPC üst bilgileri

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.

Üst bilgiler, meta veri koleksiyonunu döndüren kullanılarak ResponseHeadersAsynceriş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 sonucunun ResponseHeadersAsync beklenmelidir.
  • Daha önce ResponseAsync (veya akış sırasında yanıt akışına) erişilmesi gerekmez. Bir yanıt döndürüldüyse, ResponseHeadersAsync anında üst bilgileri döndürür.
  • Bağlantı veya sunucu hatası varsa ve gRPC çağrısı için üst bilgiler döndürülmezse bir özel durum oluşturur.

Access gRPC fragmanları

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

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

çağrılmadan önce GetTrailers()birli ve istemci akış çağrıları beklemelidirResponseAsync:

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 çağrıdan GetTrailers()ö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ömorklara uygulamasından RpcExceptionda erişilebilir. Bir hizmet, römorkları Tamam olmayan gRPC durumuyla birlikte 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 tarihi 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.

gRPC çağrısı için son tarih ayarlamak üzere yapılandırın CallOptions.Deadline :

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 ile güvenilir gRPC hizmetleri.

Ek kaynaklar