.NET'te gRPC sorunlarını giderme

Yayınlayan James Newton-King

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 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 8 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 8 sürümüne bakın.

Bu belgede.NET üzerinde gRPC uygulamaları geliştirirken sık karşılaşılan sorunlar ele alınmaktadır.

İstemci ve hizmet SSL/TLS yapılandırması arasındaki uyuşmazlık

gRPC şablonu ve örnekleri, varsayılan olarak gRPC hizmetlerinin güvenliğini sağlamak için Aktarım Katmanı Güvenliği'ni (TLS) kullanır. gRPC istemcilerinin güvenli gRPC hizmetlerini başarıyla çağırmak için güvenli bir bağlantı kullanması gerekir.

ASP.NET Core gRPC hizmetinin TLS kullandığını uygulama başlangıcında yazılan günlüklerde doğrulayabilirsiniz. Hizmet bir HTTPS uç noktasında dinler:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Güvenli bir bağlantıyla çağrı yapmak için .NET Core istemcisinin sunucu adresinde kullanması https gerekir:

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

Tüm gRPC istemci uygulamaları TLS'i destekler. diğer dillerdeki gRPC istemcileri genellikle ile SslCredentialsyapılandırılmış kanalı gerektirir. SslCredentials istemcinin kullanacağı sertifikayı belirtir ve güvenli olmayan kimlik bilgileri yerine kullanılması gerekir. Farklı gRPC istemci uygulamalarını TLS kullanacak şekilde yapılandırma örnekleri için bkz . gRPC Kimlik Doğrulaması.

Güvenilmeyen/geçersiz bir sertifikayla gRPC hizmetini çağırma

.NET gRPC istemcisi, hizmetin güvenilir bir sertifikaya sahip olmasını gerektirir. Güvenilen sertifika olmadan gRPC hizmeti çağrılırken aşağıdaki hata iletisi döndürülür:

İşlenmeyen özel durum. System.Net.Http.HttpRequestException: SSL bağlantısı kurulamadı, bkz. iç özel durum. >--- System.Security.Authentication.AuthenticationException: Uzak sertifika doğrulama yordamına göre geçersiz.

Uygulamanızı yerel olarak test ediyorsanız ve ASP.NET Core HTTPS geliştirme sertifikasına güvenilmiyorsa bu hatayı görebilirsiniz. Bu sorunu düzeltme yönergeleri için bkz . Windows ve macOS'ta ASP.NET Core HTTPS geliştirme sertifikasına güvenme.

Başka bir makinede gRPC hizmetini çağırıyorsanız ve sertifikaya güvenemiyorsanız, gRPC istemcisi geçersiz sertifikayı yoksayacak şekilde yapılandırılabilir. Aşağıdaki kod, güvenilen sertifika olmadan çağrılara izin vermek için kullanır HttpClientHandler.ServerCertificateCustomValidationCallback :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

gRPC istemci fabrikası, güvenilir bir sertifika olmadan çağrılara izin verir. İstemcide ConfigurePrimaryHttpMessageHandler işleyiciyi yapılandırmak için uzantı yöntemini kullanın:


var services = new ServiceCollection();

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback =
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Uyarı

Güvenilmeyen sertifikalar yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman geçerli sertifikalar kullanmalıdır.

.NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma

.NET gRPC istemcisi, sunucu adresinde belirtim yaparak http güvenli olmayan gRPC hizmetlerini çağırabilir. Örneğin, GrpcChannel.ForAddress("http://localhost:5000").

Bir uygulamanın kullandığı .NET sürümüne bağlı olarak güvenli olmayan gRPC hizmetlerini çağırmak için bazı ek gereksinimler vardır:

Önemli

Güvenli olmayan gRPC hizmetleri, yalnızca HTTP/2 bağlantı noktasında barındırılmalıdır. Daha fazla bilgi için bkz . ASP.NET Çekirdek protokol anlaşması.

macOS üzerinde ASP.NET Core gRPC uygulaması başlatılamıyor

Kestrel , .NET 8 öncesi macOS üzerinde TLS ile HTTP/2'nin desteklemiyor. ASP.NET Core gRPC şablonu ve örnekleri varsayılan olarak TLS kullanır. gRPC sunucusunu başlatmayı denediğinizde aşağıdaki hata iletisini görürsünüz:

IPv4 geri döngü arabirimine bağlanılamıyor https://localhost:5001 : 'EKSIK ALPN desteği nedeniyle macOS'ta TLS üzerinden HTTP/2 desteklenmiyor.'.

.NET 7 ve önceki sürümlerde bu soruna geçici bir çözüm bulmak için ve gRPC istemcisini TLS olmadan HTTP/2 kullanacak şekilde yapılandırınKestrel. Bunu yalnızca geliştirme sırasında yapmalısınız. TLS kullanılmaması gRPC iletilerinin şifreleme olmadan gönderilmesine neden olur. Daha fazla bilgi için bkz . Asp.Net Core 7.0: macOS üzerinde ASP.NET Core gRPC uygulaması başlatılamıyor.

gRPC C# varlıkları dosyalardan .proto oluşturulan kodlar değildir

Somut istemcilerin ve hizmet temel sınıflarının gRPC kod oluşturması için protobuf dosyalarının ve araçlarının bir projeden başvurulacağı gerekir. Şunları eklemeniz gerekir:

gRPC C# varlıkları oluşturma hakkında daha fazla bilgi için bkz . C# ile gRPC hizmetleri.

gRPC hizmetlerini barındıran bir ASP.NET Core web uygulaması yalnızca hizmet temel sınıfının oluşturulmasına ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

gRPC çağrıları yapan bir gRPC istemci uygulaması yalnızca oluşturulan somut istemciye ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

WPF projeleri dosyalardan .proto gRPC C# varlıkları oluşturamıyor

WPF projelerinin gRPC kod oluşturmanın düzgün çalışmasını engelleyen bilinen bir sorunu vardır. WPF projesinde başvurularak Grpc.Tools oluşturulan tüm gRPC türleri ve .proto dosyalar kullanıldığında derleme hataları oluşturur:

hata CS0246: 'MyGrpcServices' türü veya ad alanı adı bulunamadı (using yönergesi veya derleme başvurusu eksik mi?)

Bu soruna şu şekilde geçici bir çözüm bulabilirsiniz:

  1. Yeni bir .NET Core sınıf kitaplığı projesi oluşturun.
  2. Yeni projede, dosyalardan .protoC# kod oluşturmayı etkinleştirmek için başvurular ekleyin:
  3. WPF uygulamasında, yeni projeye bir başvuru ekleyin.

WPF uygulaması, yeni sınıf kitaplığı projesinden gRPC tarafından oluşturulan türleri kullanabilir.

Bir alt dizinde barındırılan gRPC hizmetlerini çağırma

Uyarı

Birçok üçüncü taraf gRPC aracı, alt dizinlerde barındırılan hizmetleri desteklemez. Kök dizin olarak gRPC barındırmanın bir yolunu bulmayı düşünün.

gRPC çağrıları yapılırken gRPC kanalının adresinin yol bileşeni yoksayılır. Örneğin, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") hizmet için gRPC çağrılarını yönlendirmek için kullanmaz ignored_path .

gRPC standartlaştırılmış, açıklayıcı bir adres yapısına sahip olduğundan adres yolu yoksayılır. gRPC adresi paket, hizmet ve yöntem adlarını birleştirir: https://localhost:5001/PackageName.ServiceName/MethodName.

Bir uygulamanın gRPC çağrıları içeren bir yol içermesi gereken bazı senaryolar vardır. Örneğin, bir ASP.NET Core gRPC uygulaması bir IIS dizininde barındırıldığında ve dizinin isteğe dahil edilmesi gerektiğinde. Bir yol gerektiğinde, aşağıda belirtilen özel SubdirectoryHandler kullanılarak gRPC çağrısına eklenebilir:

public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler gRPC kanalı oluşturulduğunda kullanılır.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

Yukarıdaki kod:

  • yolu /MyAppile bir SubdirectoryHandler oluşturur.
  • Bir kanalı kullanacak SubdirectoryHandlerşekilde yapılandırıyor.
  • ile SayHelloAsyncgRPC hizmetini çağırır. gRPC çağrısı adresine https://localhost:5001/MyApp/greet.Greeter/SayHellogönderilir.

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile SubdirectoryHandler yapılandırılabilir.

gRPC istemcisini HTTP/3 kullanacak şekilde yapılandırma

.NET gRPC istemcisi .NET 6 veya üzeri ile HTTP/3'i destekler. Sunucu, istemciye sunucunun HTTP/3'i desteklediğini belirten bir alt-svc yanıt üst bilgisi gönderirse, istemci bağlantıyı otomatik olarak HTTP/3'e yükseltecektir. Daha fazla bilgi için bkz . ASP.NET Core Kestrel web sunucusuyla HTTP/3 kullanma.

bir DelegatingHandler gRPC istemcisini HTTP/3 kullanmaya zorlamak için kullanılabilir. HTTP/3'ün zorlenmesi, isteği yükseltme ek yükünü önler. HTTP/3'i aşağıdakine benzer bir kodla zorlayın:

public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler gRPC kanalı oluşturulduğunda kullanılır. Aşağıdaki kod kullanmak Http3Handlerüzere yapılandırılmış bir kanal oluşturur.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile Http3Handler yapılandırılabilir.

Alpine Linux üzerinde gRPC oluşturma

Paket, Grpc.Tools adlı protocpaketlenmiş yerel ikili dosyasını kullanarak dosyalardan .proto .NET türleri oluşturur. Alpine Linux gibi içindeki yerel ikili dosyalar tarafından desteklenmeyen platformlarda Grpc.ToolsgRPC uygulamaları oluşturmak için ek adımlar gereklidir.

Önceden kod oluşturma

Çözümlerden biri önceden kod oluşturmaktır.

  1. Dosyaları ve paket başvurularını Grpc.Tools yeni bir projeye taşıyın.proto.
  2. Projeyi NuGet paketi olarak yayımlayın ve bir NuGet akışına yükleyin.
  3. NuGet paketine başvurmak için uygulamayı güncelleştirin.

Yukarıdaki adımlarda, kod önceden oluşturulduğundan uygulamanın artık derlenmesi gerekmez Grpc.Tools .

Yerel ikili dosyaları özelleştirme Grpc.Tools

Grpc.Tools özel yerel ikili dosyaları kullanmayı destekler. Bu özellik, gRPC araçlarının paketlenmiş yerel ikili dosyalarının desteklemez olduğu ortamlarda çalışmasını sağlar.

Derleme veya alma protoc ve grpc_csharp_plugin yerel ikili dosyalar oluşturma ve bunları kullanmak üzere yapılandırma Grpc.Tools . Aşağıdaki ortam değişkenlerini ayarlayarak yerel ikili dosyaları yapılandırın:

  • PROTOBUF_PROTOC - Protokol arabellekleri derleyicisinin tam yolu
  • GRPC_PROTOC_PLUGIN - grpc_csharp_plugin tam yolu

Alpine Linux için adresinde protokol arabellekleri derleyicisi ve gRPC eklentileri https://pkgs.alpinelinux.org/için topluluk tarafından sağlanan paketler vardır.

# Build or install the binaries for your architecture.

# For Alpine Linux, the grpc-plugins package can be used.
# See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Desteklenmeyen mimarilerle kullanma Grpc.Tools hakkında daha fazla bilgi için gRPC derleme tümleştirme belgelerine bakın.

gRPC çağrısı zaman aşımı HttpClient.Timeout

HttpClient varsayılan olarak 100 saniyelik zaman aşımı ile yapılandırılır. bir GrpcChannel kullanmak HttpClientüzere yapılandırılmışsa, uzun süre çalışan gRPC akış çağrıları zaman aşımı sınırı içinde tamamlanmazsa iptal edilir.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Bu hatayı düzeltmenin birkaç yolu vardır. İlki, daha büyük bir değere yapılandırmaktır HttpClient.Timeout . Timeout.InfiniteTimeSpan zaman aşımını devre dışı bırakır:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Alternatif olarak, oluşturmaktan HttpClient kaçının ve ayarlayın GrpcChannel.HttpHandler :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Bu belgede.NET üzerinde gRPC uygulamaları geliştirirken sık karşılaşılan sorunlar ele alınmaktadır.

İstemci ve hizmet SSL/TLS yapılandırması arasındaki uyuşmazlık

gRPC şablonu ve örnekleri, varsayılan olarak gRPC hizmetlerinin güvenliğini sağlamak için Aktarım Katmanı Güvenliği'ni (TLS) kullanır. gRPC istemcilerinin güvenli gRPC hizmetlerini başarıyla çağırmak için güvenli bir bağlantı kullanması gerekir.

ASP.NET Core gRPC hizmetinin TLS kullandığını uygulama başlangıcında yazılan günlüklerde doğrulayabilirsiniz. Hizmet bir HTTPS uç noktasında dinler:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Güvenli bir bağlantıyla çağrı yapmak için .NET Core istemcisinin sunucu adresinde kullanması https gerekir:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Tüm gRPC istemci uygulamaları TLS'i destekler. diğer dillerdeki gRPC istemcileri genellikle ile SslCredentialsyapılandırılmış kanalı gerektirir. SslCredentials istemcinin kullanacağı sertifikayı belirtir ve güvenli olmayan kimlik bilgileri yerine kullanılması gerekir. Farklı gRPC istemci uygulamalarını TLS kullanacak şekilde yapılandırma örnekleri için bkz . gRPC Kimlik Doğrulaması.

Güvenilmeyen/geçersiz bir sertifikayla gRPC hizmetini çağırma

.NET gRPC istemcisi, hizmetin güvenilir bir sertifikaya sahip olmasını gerektirir. Güvenilen sertifika olmadan gRPC hizmeti çağrılırken aşağıdaki hata iletisi döndürülür:

İşlenmeyen özel durum. System.Net.Http.HttpRequestException: SSL bağlantısı kurulamadı, bkz. iç özel durum. >--- System.Security.Authentication.AuthenticationException: Uzak sertifika doğrulama yordamına göre geçersiz.

Uygulamanızı yerel olarak test ediyorsanız ve ASP.NET Core HTTPS geliştirme sertifikasına güvenilmiyorsa bu hatayı görebilirsiniz. Bu sorunu düzeltme yönergeleri için bkz . Windows ve macOS'ta ASP.NET Core HTTPS geliştirme sertifikasına güvenme.

Başka bir makinede gRPC hizmetini çağırıyorsanız ve sertifikaya güvenemiyorsanız, gRPC istemcisi geçersiz sertifikayı yoksayacak şekilde yapılandırılabilir. Aşağıdaki kod, güvenilen sertifika olmadan çağrılara izin vermek için kullanır HttpClientHandler.ServerCertificateCustomValidationCallback :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

gRPC istemci fabrikası, güvenilir bir sertifika olmadan çağrılara izin verir. İstemcide ConfigurePrimaryHttpMessageHandler işleyiciyi yapılandırmak için uzantı yöntemini kullanın:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Uyarı

Güvenilmeyen sertifikalar yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman geçerli sertifikalar kullanmalıdır.

.NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma

.NET gRPC istemcisi, sunucu adresinde belirtim yaparak http güvenli olmayan gRPC hizmetlerini çağırabilir. Örneğin, GrpcChannel.ForAddress("http://localhost:5000").

Bir uygulamanın kullandığı .NET sürümüne bağlı olarak güvenli olmayan gRPC hizmetlerini çağırmak için bazı ek gereksinimler vardır:

  • .NET 5 veya üzeri için Grpc.Net.Client sürüm 2.32.0 veya üzeri gerekir.

  • .NET Core 3.x için ek yapılandırma gerekir. Uygulamanın anahtarını olarak trueayarlaması System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport gerekir:

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Anahtar System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport yalnızca .NET Core 3.x için gereklidir. .NET 5'te hiçbir şey yapmaz ve gerekli değildir.

Önemli

Güvenli olmayan gRPC hizmetleri, yalnızca HTTP/2 bağlantı noktasında barındırılmalıdır. Daha fazla bilgi için bkz . ASP.NET Çekirdek protokol anlaşması.

macOS üzerinde ASP.NET Core gRPC uygulaması başlatılamıyor

Kestrel , .NET 8 öncesi macOS üzerinde TLS ile HTTP/2'nin desteklemiyor. ASP.NET Core gRPC şablonu ve örnekleri varsayılan olarak TLS kullanır. gRPC sunucusunu başlatmayı denediğinizde aşağıdaki hata iletisini görürsünüz:

IPv4 geri döngü arabirimine bağlanılamıyor https://localhost:5001 : 'EKSIK ALPN desteği nedeniyle macOS'ta TLS üzerinden HTTP/2 desteklenmiyor.'.

.NET 7 ve önceki sürümlerde bu soruna geçici bir çözüm bulmak için ve gRPC istemcisini TLS olmadan HTTP/2 kullanacak şekilde yapılandırınKestrel. Bunu yalnızca geliştirme sırasında yapmalısınız. TLS kullanılmaması gRPC iletilerinin şifreleme olmadan gönderilmesine neden olur.

Kestrel içinde Program.csTLS olmadan bir HTTP/2 uç noktası yapılandırmalıdır:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • Yukarıdaki kodda localhost bağlantı noktası numarasını 5287 gRPC hizmeti projesinde Properties/launchSettings.json belirtilen (değilHTTPS) bağlantı noktası numarasıyla HTTP değiştirin.

BIR HTTP/2 uç noktası TLS olmadan yapılandırıldığında, uç noktanın ListenOptions.Protocols değeri olarak HttpProtocols.Http2ayarlanmalıdır. HttpProtocols.Http1AndHttp2 HTTP/2 anlaşması yapmak için TLS gerektiğinden kullanılamaz. TLS olmadan, uç noktaya yönelik tüm bağlantılar varsayılan olarak HTTP/1.1'dir ve gRPC çağrıları başarısız olur.

gRPC istemcisi de TLS kullanmayacak şekilde yapılandırılmalıdır. Daha fazla bilgi için bkz . .NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma.

Uyarı

TLS olmadan HTTP/2 yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman aktarım güvenliğini kullanmalıdır. Daha fazla bilgi için bkz . ASP.NET Core için gRPC'de güvenlikle ilgili dikkat edilmesi gerekenler.

gRPC C# varlıkları dosyalardan .proto oluşturulan kodlar değildir

Somut istemcilerin ve hizmet temel sınıflarının gRPC kod oluşturması için protobuf dosyalarının ve araçlarının bir projeden başvurulacağı gerekir. Şunları eklemeniz gerekir:

gRPC C# varlıkları oluşturma hakkında daha fazla bilgi için bkz . C# ile gRPC hizmetleri.

gRPC hizmetlerini barındıran bir ASP.NET Core web uygulaması yalnızca hizmet temel sınıfının oluşturulmasına ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

gRPC çağrıları yapan bir gRPC istemci uygulaması yalnızca oluşturulan somut istemciye ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

WPF projeleri dosyalardan .proto gRPC C# varlıkları oluşturamıyor

WPF projelerinin gRPC kod oluşturmanın düzgün çalışmasını engelleyen bilinen bir sorunu vardır. WPF projesinde başvurularak Grpc.Tools oluşturulan tüm gRPC türleri ve .proto dosyalar kullanıldığında derleme hataları oluşturur:

hata CS0246: 'MyGrpcServices' türü veya ad alanı adı bulunamadı (using yönergesi veya derleme başvurusu eksik mi?)

Bu soruna şu şekilde geçici bir çözüm bulabilirsiniz:

  1. Yeni bir .NET Core sınıf kitaplığı projesi oluşturun.
  2. Yeni projede, dosyalardan .protoC# kod oluşturmayı etkinleştirmek için başvurular ekleyin:
  3. WPF uygulamasında, yeni projeye bir başvuru ekleyin.

WPF uygulaması, yeni sınıf kitaplığı projesinden gRPC tarafından oluşturulan türleri kullanabilir.

Bir alt dizinde barındırılan gRPC hizmetlerini çağırma

Uyarı

Birçok üçüncü taraf gRPC aracı, alt dizinlerde barındırılan hizmetleri desteklemez. Kök dizin olarak gRPC barındırmanın bir yolunu bulmayı düşünün.

gRPC çağrıları yapılırken gRPC kanalının adresinin yol bileşeni yoksayılır. Örneğin, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") hizmet için gRPC çağrılarını yönlendirmek için kullanmaz ignored_path .

gRPC standartlaştırılmış, açıklayıcı bir adres yapısına sahip olduğundan adres yolu yoksayılır. gRPC adresi paket, hizmet ve yöntem adlarını birleştirir: https://localhost:5001/PackageName.ServiceName/MethodName.

Bir uygulamanın gRPC çağrıları içeren bir yol içermesi gereken bazı senaryolar vardır. Örneğin, bir ASP.NET Core gRPC uygulaması bir IIS dizininde barındırıldığında ve dizinin isteğe dahil edilmesi gerektiğinde. Bir yol gerektiğinde, aşağıda belirtilen özel SubdirectoryHandler kullanılarak gRPC çağrısına eklenebilir:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler gRPC kanalı oluşturulduğunda kullanılır.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Yukarıdaki kod:

  • yolu /MyAppile bir SubdirectoryHandler oluşturur.
  • Bir kanalı kullanacak SubdirectoryHandlerşekilde yapılandırıyor.
  • ile SayHelloAsyncgRPC hizmetini çağırır. gRPC çağrısı adresine https://localhost:5001/MyApp/greet.Greeter/SayHellogönderilir.

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile SubdirectoryHandler yapılandırılabilir.

gRPC istemcisini HTTP/3 kullanacak şekilde yapılandırma

.NET gRPC istemcisi .NET 6 veya üzeri ile HTTP/3'i destekler. Sunucu, istemciye sunucunun HTTP/3'i desteklediğini belirten bir alt-svc yanıt üst bilgisi gönderirse, istemci bağlantıyı otomatik olarak HTTP/3'e yükseltecektir. Sunucuda HTTP/3'i etkinleştirme hakkında bilgi için bkz . ASP.NET Core Kestrel web sunucusuyla HTTP/3 kullanma.

.NET 8'de HTTP/3 desteği varsayılan olarak etkindir. .NET 6 ve .NET 7'de HTTP/3 desteğinin proje dosyasındaki bir yapılandırma bayrağı aracılığıyla etkinleştirilmesi gerekir:

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>

System.Net.SocketsHttpHandler.Http3SupportAppContext.SetSwitch kullanılarak da ayarlanabilir.

bir DelegatingHandler gRPC istemcisini HTTP/3 kullanmaya zorlamak için kullanılabilir. HTTP/3'ün zorlenmesi, isteği yükseltme ek yükünü önler. HTTP/3'i aşağıdakine benzer bir kodla zorlayın:

/// <summary>
/// A delegating handler that changes the request HTTP version to HTTP/3.
/// </summary>
public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler gRPC kanalı oluşturulduğunda kullanılır. Aşağıdaki kod kullanmak Http3Handlerüzere yapılandırılmış bir kanal oluşturur.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile Http3Handler yapılandırılabilir.

Alpine Linux üzerinde gRPC oluşturma

Paket, Grpc.Tools adlı protocpaketlenmiş yerel ikili dosyasını kullanarak dosyalardan .proto .NET türleri oluşturur. Alpine Linux gibi içindeki yerel ikili dosyalar tarafından desteklenmeyen platformlarda Grpc.ToolsgRPC uygulamaları oluşturmak için ek adımlar gereklidir.

Önceden kod oluşturma

Çözümlerden biri önceden kod oluşturmaktır.

  1. Dosyaları ve paket başvurularını Grpc.Tools yeni bir projeye taşıyın.proto.
  2. Projeyi NuGet paketi olarak yayımlayın ve bir NuGet akışına yükleyin.
  3. NuGet paketine başvurmak için uygulamayı güncelleştirin.

Yukarıdaki adımlarda, kod önceden oluşturulduğundan uygulamanın artık derlenmesi gerekmez Grpc.Tools .

Yerel ikili dosyaları özelleştirme Grpc.Tools

Grpc.Tools özel yerel ikili dosyaları kullanmayı destekler. Bu özellik, gRPC araçlarının paketlenmiş yerel ikili dosyalarının desteklemez olduğu ortamlarda çalışmasını sağlar.

Derleme veya alma protoc ve grpc_csharp_plugin yerel ikili dosyalar oluşturma ve bunları kullanmak üzere yapılandırma Grpc.Tools . Aşağıdaki ortam değişkenlerini ayarlayarak yerel ikili dosyaları yapılandırın:

  • PROTOBUF_PROTOC - Protokol arabellekleri derleyicisinin tam yolu
  • GRPC_PROTOC_PLUGIN - grpc_csharp_plugin tam yolu

Alpine Linux için adresinde protokol arabellekleri derleyicisi ve gRPC eklentileri https://pkgs.alpinelinux.org/için topluluk tarafından sağlanan paketler vardır.

# Build or install the binaries for your architecture.

# For Alpine Linux, the grpc-plugins package can be used.
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Desteklenmeyen mimarilerle kullanma Grpc.Tools hakkında daha fazla bilgi için gRPC derleme tümleştirme belgelerine bakın.

gRPC çağrısı zaman aşımı HttpClient.Timeout

HttpClient varsayılan olarak 100 saniyelik zaman aşımı ile yapılandırılır. bir GrpcChannel kullanmak HttpClientüzere yapılandırılmışsa, uzun süre çalışan gRPC akış çağrıları zaman aşımı sınırı içinde tamamlanmazsa iptal edilir.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Bu hatayı düzeltmenin birkaç yolu vardır. İlki, daha büyük bir değere yapılandırmaktır HttpClient.Timeout . Timeout.InfiniteTimeSpan zaman aşımını devre dışı bırakır:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Alternatif olarak, oluşturmaktan HttpClient kaçının ve ayarlayın GrpcChannel.HttpHandler :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Bu belgede.NET üzerinde gRPC uygulamaları geliştirirken sık karşılaşılan sorunlar ele alınmaktadır.

İstemci ve hizmet SSL/TLS yapılandırması arasındaki uyuşmazlık

gRPC şablonu ve örnekleri, varsayılan olarak gRPC hizmetlerinin güvenliğini sağlamak için Aktarım Katmanı Güvenliği'ni (TLS) kullanır. gRPC istemcilerinin güvenli gRPC hizmetlerini başarıyla çağırmak için güvenli bir bağlantı kullanması gerekir.

ASP.NET Core gRPC hizmetinin TLS kullandığını uygulama başlangıcında yazılan günlüklerde doğrulayabilirsiniz. Hizmet bir HTTPS uç noktasında dinler:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Güvenli bir bağlantıyla çağrı yapmak için .NET Core istemcisinin sunucu adresinde kullanması https gerekir:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Tüm gRPC istemci uygulamaları TLS'i destekler. diğer dillerdeki gRPC istemcileri genellikle ile SslCredentialsyapılandırılmış kanalı gerektirir. SslCredentials istemcinin kullanacağı sertifikayı belirtir ve güvenli olmayan kimlik bilgileri yerine kullanılması gerekir. Farklı gRPC istemci uygulamalarını TLS kullanacak şekilde yapılandırma örnekleri için bkz . gRPC Kimlik Doğrulaması.

Güvenilmeyen/geçersiz bir sertifikayla gRPC hizmetini çağırma

.NET gRPC istemcisi, hizmetin güvenilir bir sertifikaya sahip olmasını gerektirir. Güvenilen sertifika olmadan gRPC hizmeti çağrılırken aşağıdaki hata iletisi döndürülür:

İşlenmeyen özel durum. System.Net.Http.HttpRequestException: SSL bağlantısı kurulamadı, bkz. iç özel durum. >--- System.Security.Authentication.AuthenticationException: Uzak sertifika doğrulama yordamına göre geçersiz.

Uygulamanızı yerel olarak test ediyorsanız ve ASP.NET Core HTTPS geliştirme sertifikasına güvenilmiyorsa bu hatayı görebilirsiniz. Bu sorunu düzeltme yönergeleri için bkz . Windows ve macOS'ta ASP.NET Core HTTPS geliştirme sertifikasına güvenme.

Başka bir makinede gRPC hizmetini çağırıyorsanız ve sertifikaya güvenemiyorsanız, gRPC istemcisi geçersiz sertifikayı yoksayacak şekilde yapılandırılabilir. Aşağıdaki kod, güvenilen sertifika olmadan çağrılara izin vermek için kullanır HttpClientHandler.ServerCertificateCustomValidationCallback :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

gRPC istemci fabrikası, güvenilir bir sertifika olmadan çağrılara izin verir. İstemcide ConfigurePrimaryHttpMessageHandler işleyiciyi yapılandırmak için uzantı yöntemini kullanın:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Uyarı

Güvenilmeyen sertifikalar yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman geçerli sertifikalar kullanmalıdır.

.NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma

.NET gRPC istemcisi, sunucu adresinde belirtim yaparak http güvenli olmayan gRPC hizmetlerini çağırabilir. Örneğin, GrpcChannel.ForAddress("http://localhost:5000").

Bir uygulamanın kullandığı .NET sürümüne bağlı olarak güvenli olmayan gRPC hizmetlerini çağırmak için bazı ek gereksinimler vardır:

  • .NET 5 veya üzeri için Grpc.Net.Client sürüm 2.32.0 veya üzeri gerekir.

  • .NET Core 3.x için ek yapılandırma gerekir. Uygulamanın anahtarını olarak trueayarlaması System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport gerekir:

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Anahtar System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport yalnızca .NET Core 3.x için gereklidir. .NET 5'te hiçbir şey yapmaz ve gerekli değildir.

Önemli

Güvenli olmayan gRPC hizmetleri, yalnızca HTTP/2 bağlantı noktasında barındırılmalıdır. Daha fazla bilgi için bkz . ASP.NET Çekirdek protokol anlaşması.

macOS üzerinde ASP.NET Core gRPC uygulaması başlatılamıyor

Kestrel , .NET 8 öncesi macOS üzerinde TLS ile HTTP/2'nin desteklemiyor. ASP.NET Core gRPC şablonu ve örnekleri varsayılan olarak TLS kullanır. gRPC sunucusunu başlatmayı denediğinizde aşağıdaki hata iletisini görürsünüz:

IPv4 geri döngü arabirimine bağlanılamıyor https://localhost:5001 : 'EKSIK ALPN desteği nedeniyle macOS'ta TLS üzerinden HTTP/2 desteklenmiyor.'.

.NET 7 ve önceki sürümlerde bu soruna geçici bir çözüm bulmak için ve gRPC istemcisini TLS olmadan HTTP/2 kullanacak şekilde yapılandırınKestrel. Bunu yalnızca geliştirme sırasında yapmalısınız. TLS kullanılmaması gRPC iletilerinin şifreleme olmadan gönderilmesine neden olur.

Kestrel içinde Program.csTLS olmadan bir HTTP/2 uç noktası yapılandırmalıdır:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

BIR HTTP/2 uç noktası TLS olmadan yapılandırıldığında, uç noktanın ListenOptions.Protocols değeri olarak HttpProtocols.Http2ayarlanmalıdır. HttpProtocols.Http1AndHttp2 HTTP/2 anlaşması yapmak için TLS gerektiğinden kullanılamaz. TLS olmadan, uç noktaya yönelik tüm bağlantılar varsayılan olarak HTTP/1.1'dir ve gRPC çağrıları başarısız olur.

gRPC istemcisi de TLS kullanmayacak şekilde yapılandırılmalıdır. Daha fazla bilgi için bkz . .NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma.

Uyarı

TLS olmadan HTTP/2 yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman aktarım güvenliğini kullanmalıdır. Daha fazla bilgi için bkz . ASP.NET Core için gRPC'de güvenlikle ilgili dikkat edilmesi gerekenler.

gRPC C# varlıkları dosyalardan .proto oluşturulan kodlar değildir

Somut istemcilerin ve hizmet temel sınıflarının gRPC kod oluşturması için protobuf dosyalarının ve araçlarının bir projeden başvurulacağı gerekir. Şunları eklemeniz gerekir:

gRPC C# varlıkları oluşturma hakkında daha fazla bilgi için bkz . C# ile gRPC hizmetleri.

gRPC hizmetlerini barındıran bir ASP.NET Core web uygulaması yalnızca hizmet temel sınıfının oluşturulmasına ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

gRPC çağrıları yapan bir gRPC istemci uygulaması yalnızca oluşturulan somut istemciye ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

WPF projeleri dosyalardan .proto gRPC C# varlıkları oluşturamıyor

WPF projelerinin gRPC kod oluşturmanın düzgün çalışmasını engelleyen bilinen bir sorunu vardır. WPF projesinde başvurularak Grpc.Tools oluşturulan tüm gRPC türleri ve .proto dosyalar kullanıldığında derleme hataları oluşturur:

hata CS0246: 'MyGrpcServices' türü veya ad alanı adı bulunamadı (using yönergesi veya derleme başvurusu eksik mi?)

Bu soruna şu şekilde geçici bir çözüm bulabilirsiniz:

  1. Yeni bir .NET Core sınıf kitaplığı projesi oluşturun.
  2. Yeni projede, dosyalardan .protoC# kod oluşturmayı etkinleştirmek için başvurular ekleyin:
  3. WPF uygulamasında, yeni projeye bir başvuru ekleyin.

WPF uygulaması, yeni sınıf kitaplığı projesinden gRPC tarafından oluşturulan türleri kullanabilir.

Bir alt dizinde barındırılan gRPC hizmetlerini çağırma

Uyarı

Birçok üçüncü taraf gRPC aracı, alt dizinlerde barındırılan hizmetleri desteklemez. Kök dizin olarak gRPC barındırmanın bir yolunu bulmayı düşünün.

gRPC çağrıları yapılırken gRPC kanalının adresinin yol bileşeni yoksayılır. Örneğin, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") hizmet için gRPC çağrılarını yönlendirmek için kullanmaz ignored_path .

gRPC standartlaştırılmış, açıklayıcı bir adres yapısına sahip olduğundan adres yolu yoksayılır. gRPC adresi paket, hizmet ve yöntem adlarını birleştirir: https://localhost:5001/PackageName.ServiceName/MethodName.

Bir uygulamanın gRPC çağrıları içeren bir yol içermesi gereken bazı senaryolar vardır. Örneğin, bir ASP.NET Core gRPC uygulaması bir IIS dizininde barındırıldığında ve dizinin isteğe dahil edilmesi gerektiğinde. Bir yol gerektiğinde, aşağıda belirtilen özel SubdirectoryHandler kullanılarak gRPC çağrısına eklenebilir:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler gRPC kanalı oluşturulduğunda kullanılır.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Yukarıdaki kod:

  • yolu /MyAppile bir SubdirectoryHandler oluşturur.
  • Bir kanalı kullanacak SubdirectoryHandlerşekilde yapılandırıyor.
  • ile SayHelloAsyncgRPC hizmetini çağırır. gRPC çağrısı adresine https://localhost:5001/MyApp/greet.Greeter/SayHellogönderilir.

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile SubdirectoryHandler yapılandırılabilir.

gRPC çağrısı zaman aşımı HttpClient.Timeout

HttpClient varsayılan olarak 100 saniyelik zaman aşımı ile yapılandırılır. bir GrpcChannel kullanmak HttpClientüzere yapılandırılmışsa, uzun süre çalışan gRPC akış çağrıları zaman aşımı sınırı içinde tamamlanmazsa iptal edilir.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Bu hatayı düzeltmenin birkaç yolu vardır. İlki, daha büyük bir değere yapılandırmaktır HttpClient.Timeout . Timeout.InfiniteTimeSpan zaman aşımını devre dışı bırakır:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Alternatif olarak, oluşturmaktan HttpClient kaçının ve ayarlayın GrpcChannel.HttpHandler :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Bu belgede.NET üzerinde gRPC uygulamaları geliştirirken sık karşılaşılan sorunlar ele alınmaktadır.

İstemci ve hizmet SSL/TLS yapılandırması arasındaki uyuşmazlık

gRPC şablonu ve örnekleri, varsayılan olarak gRPC hizmetlerinin güvenliğini sağlamak için Aktarım Katmanı Güvenliği'ni (TLS) kullanır. gRPC istemcilerinin güvenli gRPC hizmetlerini başarıyla çağırmak için güvenli bir bağlantı kullanması gerekir.

ASP.NET Core gRPC hizmetinin TLS kullandığını uygulama başlangıcında yazılan günlüklerde doğrulayabilirsiniz. Hizmet bir HTTPS uç noktasında dinler:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Güvenli bir bağlantıyla çağrı yapmak için .NET Core istemcisinin sunucu adresinde kullanması https gerekir:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Tüm gRPC istemci uygulamaları TLS'i destekler. diğer dillerdeki gRPC istemcileri genellikle ile SslCredentialsyapılandırılmış kanalı gerektirir. SslCredentials istemcinin kullanacağı sertifikayı belirtir ve güvenli olmayan kimlik bilgileri yerine kullanılması gerekir. Farklı gRPC istemci uygulamalarını TLS kullanacak şekilde yapılandırma örnekleri için bkz . gRPC Kimlik Doğrulaması.

Güvenilmeyen/geçersiz bir sertifikayla gRPC hizmetini çağırma

.NET gRPC istemcisi, hizmetin güvenilir bir sertifikaya sahip olmasını gerektirir. Güvenilen sertifika olmadan gRPC hizmeti çağrılırken aşağıdaki hata iletisi döndürülür:

İşlenmeyen özel durum. System.Net.Http.HttpRequestException: SSL bağlantısı kurulamadı, bkz. iç özel durum. >--- System.Security.Authentication.AuthenticationException: Uzak sertifika doğrulama yordamına göre geçersiz.

Uygulamanızı yerel olarak test ediyorsanız ve ASP.NET Core HTTPS geliştirme sertifikasına güvenilmiyorsa bu hatayı görebilirsiniz. Bu sorunu düzeltme yönergeleri için bkz . Windows ve macOS'ta ASP.NET Core HTTPS geliştirme sertifikasına güvenme.

Başka bir makinede gRPC hizmetini çağırıyorsanız ve sertifikaya güvenemiyorsanız, gRPC istemcisi geçersiz sertifikayı yoksayacak şekilde yapılandırılabilir. Aşağıdaki kod, güvenilen sertifika olmadan çağrılara izin vermek için kullanır HttpClientHandler.ServerCertificateCustomValidationCallback :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

gRPC istemci fabrikası, güvenilir bir sertifika olmadan çağrılara izin verir. İstemcide ConfigurePrimaryHttpMessageHandler işleyiciyi yapılandırmak için uzantı yöntemini kullanın:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Uyarı

Güvenilmeyen sertifikalar yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman geçerli sertifikalar kullanmalıdır.

.NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma

.NET gRPC istemcisi, sunucu adresinde belirtim yaparak http güvenli olmayan gRPC hizmetlerini çağırabilir. Örneğin, GrpcChannel.ForAddress("http://localhost:5000").

Bir uygulamanın kullandığı .NET sürümüne bağlı olarak güvenli olmayan gRPC hizmetlerini çağırmak için bazı ek gereksinimler vardır:

  • .NET 5 veya üzeri için Grpc.Net.Client sürüm 2.32.0 veya üzeri gerekir.

  • .NET Core 3.x için ek yapılandırma gerekir. Uygulamanın anahtarını olarak trueayarlaması System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport gerekir:

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Anahtar System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport yalnızca .NET Core 3.x için gereklidir. .NET 5'te hiçbir şey yapmaz ve gerekli değildir.

Önemli

Güvenli olmayan gRPC hizmetleri, yalnızca HTTP/2 bağlantı noktasında barındırılmalıdır. Daha fazla bilgi için bkz . ASP.NET Çekirdek protokol anlaşması.

macOS üzerinde ASP.NET Core gRPC uygulaması başlatılamıyor

Kestrel , .NET 8 öncesi macOS üzerinde TLS ile HTTP/2'nin desteklemiyor. ASP.NET Core gRPC şablonu ve örnekleri varsayılan olarak TLS kullanır. gRPC sunucusunu başlatmayı denediğinizde aşağıdaki hata iletisini görürsünüz:

IPv4 geri döngü arabirimine bağlanılamıyor https://localhost:5001 : 'EKSIK ALPN desteği nedeniyle macOS'ta TLS üzerinden HTTP/2 desteklenmiyor.'.

.NET 7 ve önceki sürümlerde bu soruna geçici bir çözüm bulmak için ve gRPC istemcisini TLS olmadan HTTP/2 kullanacak şekilde yapılandırınKestrel. Bunu yalnızca geliştirme sırasında yapmalısınız. TLS kullanılmaması gRPC iletilerinin şifreleme olmadan gönderilmesine neden olur.

Kestrel içinde Program.csTLS olmadan bir HTTP/2 uç noktası yapılandırmalıdır:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

BIR HTTP/2 uç noktası TLS olmadan yapılandırıldığında, uç noktanın ListenOptions.Protocols değeri olarak HttpProtocols.Http2ayarlanmalıdır. HttpProtocols.Http1AndHttp2 HTTP/2 anlaşması yapmak için TLS gerektiğinden kullanılamaz. TLS olmadan, uç noktaya yönelik tüm bağlantılar varsayılan olarak HTTP/1.1'dir ve gRPC çağrıları başarısız olur.

gRPC istemcisi de TLS kullanmayacak şekilde yapılandırılmalıdır. Daha fazla bilgi için bkz . .NET Core istemcisiyle güvenli olmayan gRPC hizmetlerini çağırma.

Uyarı

TLS olmadan HTTP/2 yalnızca uygulama geliştirme sırasında kullanılmalıdır. Üretim uygulamaları her zaman aktarım güvenliğini kullanmalıdır. Daha fazla bilgi için bkz . ASP.NET Core için gRPC'de güvenlikle ilgili dikkat edilmesi gerekenler.

gRPC C# varlıkları dosyalardan .proto oluşturulan kodlar değildir

Somut istemcilerin ve hizmet temel sınıflarının gRPC kod oluşturması için protobuf dosyalarının ve araçlarının bir projeden başvurulacağı gerekir. Şunları eklemeniz gerekir:

gRPC C# varlıkları oluşturma hakkında daha fazla bilgi için bkz . C# ile gRPC hizmetleri.

gRPC hizmetlerini barındıran bir ASP.NET Core web uygulaması yalnızca hizmet temel sınıfının oluşturulmasına ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

gRPC çağrıları yapan bir gRPC istemci uygulaması yalnızca oluşturulan somut istemciye ihtiyaç duyar:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

WPF projeleri dosyalardan .proto gRPC C# varlıkları oluşturamıyor

WPF projelerinin gRPC kod oluşturmanın düzgün çalışmasını engelleyen bilinen bir sorunu vardır. WPF projesinde başvurularak Grpc.Tools oluşturulan tüm gRPC türleri ve .proto dosyalar kullanıldığında derleme hataları oluşturur:

hata CS0246: 'MyGrpcServices' türü veya ad alanı adı bulunamadı (using yönergesi veya derleme başvurusu eksik mi?)

Bu soruna şu şekilde geçici bir çözüm bulabilirsiniz:

  1. Yeni bir .NET Core sınıf kitaplığı projesi oluşturun.
  2. Yeni projede, dosyalardan .protoC# kod oluşturmayı etkinleştirmek için başvurular ekleyin:
  3. WPF uygulamasında, yeni projeye bir başvuru ekleyin.

WPF uygulaması, yeni sınıf kitaplığı projesinden gRPC tarafından oluşturulan türleri kullanabilir.

Bir alt dizinde barındırılan gRPC hizmetlerini çağırma

Uyarı

Birçok üçüncü taraf gRPC aracı, alt dizinlerde barındırılan hizmetleri desteklemez. Kök dizin olarak gRPC barındırmanın bir yolunu bulmayı düşünün.

gRPC çağrıları yapılırken gRPC kanalının adresinin yol bileşeni yoksayılır. Örneğin, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") hizmet için gRPC çağrılarını yönlendirmek için kullanmaz ignored_path .

gRPC standartlaştırılmış, açıklayıcı bir adres yapısına sahip olduğundan adres yolu yoksayılır. gRPC adresi paket, hizmet ve yöntem adlarını birleştirir: https://localhost:5001/PackageName.ServiceName/MethodName.

Bir uygulamanın gRPC çağrıları içeren bir yol içermesi gereken bazı senaryolar vardır. Örneğin, bir ASP.NET Core gRPC uygulaması bir IIS dizininde barındırıldığında ve dizinin isteğe dahil edilmesi gerektiğinde. Bir yol gerektiğinde, aşağıda belirtilen özel SubdirectoryHandler kullanılarak gRPC çağrısına eklenebilir:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler gRPC kanalı oluşturulduğunda kullanılır.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Yukarıdaki kod:

  • yolu /MyAppile bir SubdirectoryHandler oluşturur.
  • Bir kanalı kullanacak SubdirectoryHandlerşekilde yapılandırıyor.
  • ile SayHelloAsyncgRPC hizmetini çağırır. gRPC çağrısı adresine https://localhost:5001/MyApp/greet.Greeter/SayHellogönderilir.

Alternatif olarak, bir istemci fabrikası kullanılarak AddHttpMessageHandlerile SubdirectoryHandler yapılandırılabilir.

gRPC çağrısı zaman aşımı HttpClient.Timeout

HttpClient varsayılan olarak 100 saniyelik zaman aşımı ile yapılandırılır. bir GrpcChannel kullanmak HttpClientüzere yapılandırılmışsa, uzun süre çalışan gRPC akış çağrıları zaman aşımı sınırı içinde tamamlanmazsa iptal edilir.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Bu hatayı düzeltmenin birkaç yolu vardır. İlki, daha büyük bir değere yapılandırmaktır HttpClient.Timeout . Timeout.InfiniteTimeSpan zaman aşımını devre dışı bırakır:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Alternatif olarak, oluşturmaktan HttpClient kaçının ve ayarlayın GrpcChannel.HttpHandler :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);