.NET Core での gRPC のトラブルシューティング
作成者: James Newton-King
このドキュメントでは、.NET で gRPC アプリを開発する際によく発生する問題について説明します。
クライアントとサービスの SSL/TLS 構成が一致しない
GRPC テンプレートとサンプルでは、トランスポート層セキュリティ (TLS) を使用して、既定で gRPC サービスをセキュリティ保護しています。 gRPC クライアントは、セキュリティ保護された gRPC サービスを正常に呼び出すために、セキュリティ保護された接続を使用する必要があります。
アプリの起動時に書き込まれたログで、ASP.NET Core gRPC サービスが TLS を使用していることを確認できます。 サービスは、HTTPS エンドポイントでリッスンします。
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
.NET Core クライアントは、サーバー アドレスで https
を使用して、セキュリティ保護された接続で呼び出しを行う必要があります。
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);
}
すべての gRPC クライアント実装で TLS をサポートしています。 他の言語の gRPC クライアントでは、通常、SslCredentials
によって構成されたチャネルが必要です。 SslCredentials
は、クライアントで使用する証明書を指定し、安全でない資格情報の代わりにそれが使用される必要があります。 さまざまな gRPC クライアント実装で TLS を使用するように構成する例については、gRPC 認証に関するページを参照してください。
信頼されていないか無効な証明書で gRPC サービスを呼び出す
.NET gRPC クライアントでは、サービスに信頼された証明書が必要です。 信頼された証明書を使用せずに gRPC サービスを呼び出すと、次のエラーメッセージが返されます。
ハンドルされていない例外です。 System.Net.Http.HttpRequestException:SSL 接続を確立できませんでした。内部例外を参照してください。 ---> System.Security.Authentication.AuthenticationException: 検証プロシージャによると、リモート証明書は無効です。
このエラーは、アプリをローカルでテストしていて、ASP.NET Core HTTPS 開発証明書が信頼されていない場合に表示されることがあります。 この問題を解決する手順については、「Windows と macOS で ASP.NET Core HTTPS 開発証明書を信頼します」を参照してください。
別のコンピューターで gRPC サービスを呼び出しており、その証明書を信頼できない場合、gRPC クライアントが無効な証明書を無視するように構成できます。 次のコードでは HttpClientHandler.ServerCertificateCustomValidationCallback を使用して、信頼された証明書を使用しない呼び出しを許可しています。
var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpHandler = httpHandler });
var client = new Greet.GreeterClient(channel);
警告
信頼されていない証明書は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常に有効な証明書を使用する必要があります。
.NET Core クライアントで安全でない gRPC サービスを呼び出す
.NET gRPC クライアントを使用する場合、サーバー アドレスで http
を指定すると、セキュリティで保護されていない gRPC サービスを呼び出すことができます。 たとえば、「 GrpcChannel.ForAddress("http://localhost:5000")
」のように入力します。
アプリで使用されている .NET バージョンによっては、セキュリティで保護されていない gRPC サービスの呼び出しには、さらに他の要件もいくつかあります。
.NET 5 以降では、Grpc.Net.Client バージョン 2.32.0 以降が必要です。
.NET Core 3.x の場合は、追加の構成が必要です。 アプリでは、
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチをtrue
に設定する必要があります。// 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);
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチは、.NET Core 3.x. でのみ必要です。 .NET 5 では、何も実行されないため、必要ではありません。
重要
セキュリティで保護されていない gRPC サービスは、HTTP/2 専用ポートでホストする必要があります。 詳細については、ASP.NET Core プロトコルのネゴシエーションに関する記事を参照してください。
MacOS で ASP.NET Core gRPC アプリを起動できない
Kestrel では、.NET 8 より前の macOS での TLS を使用する HTTP/2 はサポートされていません。 ASP.NET Core gRPC テンプレートとサンプルでは、既定で TLS を使用しています。 gRPC サーバーを起動しようとすると、次のエラー メッセージが表示されます。
Unable to bind to https://localhost:5001 on the IPv4 loopback interface:'HTTP/2 over TLS is not supported on macOS due to missing ALPN support.'. (IPv4 ループバック インターフェイスで https://localhost:5001 にバインドできません。'HTTP/2 over TLS は ALPN サポートがないため、macOS でサポートされていません。')
.NET 7 以前でこの問題を回避するには、TLS を "使わずに" HTTP/2 を使用するように Kestrel と gRPC クライアントを構成します。 これは開発時にのみ実行してください。 TLS を使用しないと、gRPC メッセージが暗号化されずに送信されます。
Kestrel では、Program.cs
に TLS を使用せずに HTTP/2 エンドポイントを構成する必要があります。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// Setup a HTTP/2 endpoint without TLS.
options.ListenLocalhost(<5287>, o => o.Protocols =
HttpProtocols.Http2);
});
- 上記のコードでは、ローカルホスト ポート番号
5287
を gRPC サービス プロジェクト内のProperties/launchSettings.json
で指定されたHTTP
(HTTPS
ではない) ポート番号に置き換えます。
HTTP/2 エンドポイントが TLS を使用せずに構成されている場合、エンドポイントの ListenOptions.Protocol を HttpProtocols.Http2
に設定する必要があります。 HTTP/2 のネゴシエートに TLS が必要であるため、HttpProtocols.Http1AndHttp2
は使用できません。 TLS を使用しない場合、エンドポイントへのすべての接続が既定で HTTP/1.1 に設定され、gRPC の呼び出しが失敗します。
GRPC クライアントでも、TLS を使用しないように構成する必要があります。 詳細については、「.NET Core クライアントで安全でない gRPC サービスを呼び出す」を参照してください。
警告
TLS を使用しない HTTP/2 は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常にトランスポート セキュリティを使用する必要があります。 詳細については、 gRPC for ASP.NET Core のセキュリティの考慮事項 に関するページを参照してください。
gRPC C# アセットが .proto
ファイルから生成されたコードでない
具象クライアントとサービス基本クラスの gRPC コード生成には、protobuf ファイルとツールをプロジェクトから参照する必要があります。 次のものを含める必要があります。
<Protobuf>
項目グループで使用する.proto
ファイル。 インポートされた.proto
ファイルをプロジェクトで参照する必要があります。- gRPC ツール パッケージ Grpc.Tools へのパッケージ参照。
gRPC C# アセットの生成の詳細については、「C# を使用した gRPC サービス」を参照してください。
gRPC サービスをホストしている ASP.NET Core Web アプリには、生成されたサービス基本クラスのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
gRPC 呼び出しを行う gRPC クライアント アプリでは、生成された具象クライアントのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
WPF プロジェクトで .proto
ファイルから gRPC C# アセットを生成できない
WPF プロジェクトには、gRPC コードの生成が正常に機能しなくなる既知の問題があります。 WPF プロジェクトで Grpc.Tools
と .proto
ファイルを参照して生成された gRPC 型は、使用すると、コンパイル エラーが発生します。
エラー CS0246:型または名前空間の名前 'tMyGrpcServices' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)
この問題は次の方法で回避できます。
- 新しい .NET Core クラス ライブラリ プロジェクトを作成します。
- 新しいプロジェクトで、参照を追加して、
.proto
ファイルからの C# コード生成を有効にします。- 次のパッケージ参照を追加します。
<Protobuf>
項目グループに.proto
ファイルを追加します。
- WPF アプリケーションで、新しいプロジェクトに参照を追加します。
WPF アプリケーションでは、新しいクラス ライブラリ プロジェクトから、gRPC によって生成された型を使用できます。
サブディレクトリでホストされている gRPC サービスの呼び出し
警告
多くのサードパーティ製 gRPC ツールでは、サブディレクトリでホストされているサービスはサポートされていません。 ルート ディレクトリとして gRPC をホストする方法を見つけることを検討してください。
gRPC 呼び出しを行うときに、gRPC チャネルのアドレスのパス コンポーネントは無視されます。 たとえば、GrpcChannel.ForAddress("https://localhost:5001/ignored_path")
では、サービスの gRPC 呼び出しをルーティングするときに ignored_path
は使用されません。
このアドレス パスが無視されるのは、gRPC には標準化された規範的なアドレス構造があるためです。 gRPC アドレスは、パッケージ名、サービス名、およびメソッド名を組み合わせたものです (https://localhost:5001/PackageName.ServiceName/MethodName
)。
アプリで gRPC 呼び出しのパスを含める必要があるシナリオがいくつかあります。 たとえば、ASP.NET Core gRPC アプリが IIS ディレクトリでホストされていて、このディレクトリを要求に含める必要がある場合などです。 パスが必要な場合は、下のように指定されたカスタム SubdirectoryHandler
を使用して、gRPC 呼び出しに追加できます。
/// <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 チャネルが作成されるときに使用されます。
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" });
上記のコードでは次の操作が行われます。
- パス
/MyApp
を使用してSubdirectoryHandler
を作成します。 SubdirectoryHandler
を使用するようにチャネルを構成します。SayHelloAsync
を使用して gRPC サービスを呼び出します。 gRPC 呼び出しがhttps://localhost:5001/MyApp/greet.Greeter/SayHello
に送信されます。
クライアント ファクトリは、SubdirectoryHandler
で AddHttpMessageHandler を使用して構成することもできます。
HTTP/3 を使用するように gRPC クライアントを構成する
.NET gRPC クライアントは、.NET 6 以降で HTTP/3 をサポートします。 HTTP/3 がサポートされることを示す alt-svc
応答ヘッダーがサーバーからクライアントに送信された場合、クライアントは自動的にその接続を HTTP/3 にアップグレードします。 サーバー上で HTTP/3 を有効にする方法については、「ASP.NET Core Kestrel Web サーバーで HTTP/3 を使用する」を参照してください。
HTTP/3 サポートは、.NET 6 ではプレビュー段階にあり、プロジェクト ファイルから構成フラグを用いて有効にする必要があります。
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>
System.Net.SocketsHttpHandler.Http3Support
は、AppContext.SetSwitch を使用して設定することもできます。
DelegatingHandler を使用すると、HTTP/3 の使用を gRPC クライアントに強制することができます。 HTTP/3 を強制することで、要求をアップグレードするというオーバーヘッドを回避できます。 HTTP/3 を強制するには、次のようなコードを使用します。
/// <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 チャネルが作成されるときに使用されます。 次のコードでは、Http3Handler
を使用するように構成されたチャンネルを作成します。
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" });
クライアント ファクトリは、Http3Handler
で AddHttpMessageHandler を使用して構成することもできます。
このドキュメントでは、.NET で gRPC アプリを開発する際によく発生する問題について説明します。
クライアントとサービスの SSL/TLS 構成が一致しない
GRPC テンプレートとサンプルでは、トランスポート層セキュリティ (TLS) を使用して、既定で gRPC サービスをセキュリティ保護しています。 gRPC クライアントは、セキュリティ保護された gRPC サービスを正常に呼び出すために、セキュリティ保護された接続を使用する必要があります。
アプリの起動時に書き込まれたログで、ASP.NET Core gRPC サービスが TLS を使用していることを確認できます。 サービスは、HTTPS エンドポイントでリッスンします。
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
.NET Core クライアントは、サーバー アドレスで https
を使用して、セキュリティ保護された接続で呼び出しを行う必要があります。
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);
}
すべての gRPC クライアント実装で TLS をサポートしています。 他の言語の gRPC クライアントでは、通常、SslCredentials
によって構成されたチャネルが必要です。 SslCredentials
は、クライアントで使用する証明書を指定し、安全でない資格情報の代わりにそれが使用される必要があります。 さまざまな gRPC クライアント実装で TLS を使用するように構成する例については、gRPC 認証に関するページを参照してください。
信頼されていないか無効な証明書で gRPC サービスを呼び出す
.NET gRPC クライアントでは、サービスに信頼された証明書が必要です。 信頼された証明書を使用せずに gRPC サービスを呼び出すと、次のエラーメッセージが返されます。
ハンドルされていない例外です。 System.Net.Http.HttpRequestException:SSL 接続を確立できませんでした。内部例外を参照してください。 ---> System.Security.Authentication.AuthenticationException: 検証プロシージャによると、リモート証明書は無効です。
このエラーは、アプリをローカルでテストしていて、ASP.NET Core HTTPS 開発証明書が信頼されていない場合に表示されることがあります。 この問題を解決する手順については、「Windows と macOS で ASP.NET Core HTTPS 開発証明書を信頼します」を参照してください。
別のコンピューターで gRPC サービスを呼び出しており、その証明書を信頼できない場合、gRPC クライアントが無効な証明書を無視するように構成できます。 次のコードでは HttpClientHandler.ServerCertificateCustomValidationCallback を使用して、信頼された証明書を使用しない呼び出しを許可しています。
var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpHandler = httpHandler });
var client = new Greet.GreeterClient(channel);
警告
信頼されていない証明書は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常に有効な証明書を使用する必要があります。
.NET Core クライアントで安全でない gRPC サービスを呼び出す
.NET gRPC クライアントを使用する場合、サーバー アドレスで http
を指定すると、セキュリティで保護されていない gRPC サービスを呼び出すことができます。 たとえば、「 GrpcChannel.ForAddress("http://localhost:5000")
」のように入力します。
アプリで使用されている .NET バージョンによっては、セキュリティで保護されていない gRPC サービスの呼び出しには、さらに他の要件もいくつかあります。
.NET 5 以降では、Grpc.Net.Client バージョン 2.32.0 以降が必要です。
.NET Core 3.x の場合は、追加の構成が必要です。 アプリでは、
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチをtrue
に設定する必要があります。// 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);
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチは、.NET Core 3.x. でのみ必要です。 .NET 5 では、何も実行されないため、必要ではありません。
重要
セキュリティで保護されていない gRPC サービスは、HTTP/2 専用ポートでホストする必要があります。 詳細については、ASP.NET Core プロトコルのネゴシエーションに関する記事を参照してください。
MacOS で ASP.NET Core gRPC アプリを起動できない
Kestrel では、.NET 8 より前の macOS での TLS を使用する HTTP/2 はサポートされていません。 ASP.NET Core gRPC テンプレートとサンプルでは、既定で TLS を使用しています。 gRPC サーバーを起動しようとすると、次のエラー メッセージが表示されます。
Unable to bind to https://localhost:5001 on the IPv4 loopback interface:'HTTP/2 over TLS is not supported on macOS due to missing ALPN support.'. (IPv4 ループバック インターフェイスで https://localhost:5001 にバインドできません。'HTTP/2 over TLS は ALPN サポートがないため、macOS でサポートされていません。')
.NET 7 以前でこの問題を回避するには、TLS を "使わずに" HTTP/2 を使用するように Kestrel と gRPC クライアントを構成します。 これは開発時にのみ実行してください。 TLS を使用しないと、gRPC メッセージが暗号化されずに送信されます。
Kestrel では、Program.cs
に TLS を使用せずに HTTP/2 エンドポイントを構成する必要があります。
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>();
});
HTTP/2 エンドポイントが TLS を使用せずに構成されている場合、エンドポイントの ListenOptions.Protocol を HttpProtocols.Http2
に設定する必要があります。 HTTP/2 のネゴシエートに TLS が必要であるため、HttpProtocols.Http1AndHttp2
は使用できません。 TLS を使用しない場合、エンドポイントへのすべての接続が既定で HTTP/1.1 に設定され、gRPC の呼び出しが失敗します。
GRPC クライアントでも、TLS を使用しないように構成する必要があります。 詳細については、「.NET Core クライアントで安全でない gRPC サービスを呼び出す」を参照してください。
警告
TLS を使用しない HTTP/2 は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常にトランスポート セキュリティを使用する必要があります。 詳細については、 gRPC for ASP.NET Core のセキュリティの考慮事項 に関するページを参照してください。
gRPC C# アセットが .proto
ファイルから生成されたコードでない
具象クライアントとサービス基本クラスの gRPC コード生成には、protobuf ファイルとツールをプロジェクトから参照する必要があります。 次のものを含める必要があります。
<Protobuf>
項目グループで使用する.proto
ファイル。 インポートされた.proto
ファイルをプロジェクトで参照する必要があります。- gRPC ツール パッケージ Grpc.Tools へのパッケージ参照。
gRPC C# アセットの生成の詳細については、「C# を使用した gRPC サービス」を参照してください。
gRPC サービスをホストしている ASP.NET Core Web アプリには、生成されたサービス基本クラスのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
gRPC 呼び出しを行う gRPC クライアント アプリでは、生成された具象クライアントのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
WPF プロジェクトで .proto
ファイルから gRPC C# アセットを生成できない
WPF プロジェクトには、gRPC コードの生成が正常に機能しなくなる既知の問題があります。 WPF プロジェクトで Grpc.Tools
と .proto
ファイルを参照して生成された gRPC 型は、使用すると、コンパイル エラーが発生します。
エラー CS0246:型または名前空間の名前 'tMyGrpcServices' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)
この問題は次の方法で回避できます。
- 新しい .NET Core クラス ライブラリ プロジェクトを作成します。
- 新しいプロジェクトで、参照を追加して、
.proto
ファイルからの C# コード生成を有効にします。- 次のパッケージ参照を追加します。
<Protobuf>
項目グループに.proto
ファイルを追加します。
- WPF アプリケーションで、新しいプロジェクトに参照を追加します。
WPF アプリケーションでは、新しいクラス ライブラリ プロジェクトから、gRPC によって生成された型を使用できます。
サブディレクトリでホストされている gRPC サービスの呼び出し
警告
多くのサードパーティ製 gRPC ツールでは、サブディレクトリでホストされているサービスはサポートされていません。 ルート ディレクトリとして gRPC をホストする方法を見つけることを検討してください。
gRPC 呼び出しを行うときに、gRPC チャネルのアドレスのパス コンポーネントは無視されます。 たとえば、GrpcChannel.ForAddress("https://localhost:5001/ignored_path")
では、サービスの gRPC 呼び出しをルーティングするときに ignored_path
は使用されません。
このアドレス パスが無視されるのは、gRPC には標準化された規範的なアドレス構造があるためです。 gRPC アドレスは、パッケージ名、サービス名、およびメソッド名を組み合わせたものです (https://localhost:5001/PackageName.ServiceName/MethodName
)。
アプリで gRPC 呼び出しのパスを含める必要があるシナリオがいくつかあります。 たとえば、ASP.NET Core gRPC アプリが IIS ディレクトリでホストされていて、このディレクトリを要求に含める必要がある場合などです。 パスが必要な場合は、下のように指定されたカスタム SubdirectoryHandler
を使用して、gRPC 呼び出しに追加できます。
/// <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 チャネルが作成されるときに使用されます。
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" });
上記のコードでは次の操作が行われます。
- パス
/MyApp
を使用してSubdirectoryHandler
を作成します。 SubdirectoryHandler
を使用するようにチャネルを構成します。SayHelloAsync
を使用して gRPC サービスを呼び出します。 gRPC 呼び出しがhttps://localhost:5001/MyApp/greet.Greeter/SayHello
に送信されます。
クライアント ファクトリは、SubdirectoryHandler
で AddHttpMessageHandler を使用して構成することもできます。
このドキュメントでは、.NET で gRPC アプリを開発する際によく発生する問題について説明します。
クライアントとサービスの SSL/TLS 構成が一致しない
GRPC テンプレートとサンプルでは、トランスポート層セキュリティ (TLS) を使用して、既定で gRPC サービスをセキュリティ保護しています。 gRPC クライアントは、セキュリティ保護された gRPC サービスを正常に呼び出すために、セキュリティ保護された接続を使用する必要があります。
アプリの起動時に書き込まれたログで、ASP.NET Core gRPC サービスが TLS を使用していることを確認できます。 サービスは、HTTPS エンドポイントでリッスンします。
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
.NET Core クライアントは、サーバー アドレスで https
を使用して、セキュリティ保護された接続で呼び出しを行う必要があります。
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);
}
すべての gRPC クライアント実装で TLS をサポートしています。 他の言語の gRPC クライアントでは、通常、SslCredentials
によって構成されたチャネルが必要です。 SslCredentials
は、クライアントで使用する証明書を指定し、安全でない資格情報の代わりにそれが使用される必要があります。 さまざまな gRPC クライアント実装で TLS を使用するように構成する例については、gRPC 認証に関するページを参照してください。
信頼されていないか無効な証明書で gRPC サービスを呼び出す
.NET gRPC クライアントでは、サービスに信頼された証明書が必要です。 信頼された証明書を使用せずに gRPC サービスを呼び出すと、次のエラーメッセージが返されます。
ハンドルされていない例外です。 System.Net.Http.HttpRequestException:SSL 接続を確立できませんでした。内部例外を参照してください。 ---> System.Security.Authentication.AuthenticationException: 検証プロシージャによると、リモート証明書は無効です。
このエラーは、アプリをローカルでテストしていて、ASP.NET Core HTTPS 開発証明書が信頼されていない場合に表示されることがあります。 この問題を解決する手順については、「Windows と macOS で ASP.NET Core HTTPS 開発証明書を信頼します」を参照してください。
別のコンピューターで gRPC サービスを呼び出しており、その証明書を信頼できない場合、gRPC クライアントが無効な証明書を無視するように構成できます。 次のコードでは HttpClientHandler.ServerCertificateCustomValidationCallback を使用して、信頼された証明書を使用しない呼び出しを許可しています。
var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpHandler = httpHandler });
var client = new Greet.GreeterClient(channel);
警告
信頼されていない証明書は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常に有効な証明書を使用する必要があります。
.NET Core クライアントで安全でない gRPC サービスを呼び出す
.NET gRPC クライアントを使用する場合、サーバー アドレスで http
を指定すると、セキュリティで保護されていない gRPC サービスを呼び出すことができます。 たとえば、「 GrpcChannel.ForAddress("http://localhost:5000")
」のように入力します。
アプリで使用されている .NET バージョンによっては、セキュリティで保護されていない gRPC サービスの呼び出しには、さらに他の要件もいくつかあります。
.NET 5 以降では、Grpc.Net.Client バージョン 2.32.0 以降が必要です。
.NET Core 3.x の場合は、追加の構成が必要です。 アプリでは、
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチをtrue
に設定する必要があります。// 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);
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
スイッチは、.NET Core 3.x. でのみ必要です。 .NET 5 では、何も実行されないため、必要ではありません。
重要
セキュリティで保護されていない gRPC サービスは、HTTP/2 専用ポートでホストする必要があります。 詳細については、ASP.NET Core プロトコルのネゴシエーションに関する記事を参照してください。
MacOS で ASP.NET Core gRPC アプリを起動できない
Kestrel では、.NET 8 より前の macOS での TLS を使用する HTTP/2 はサポートされていません。 ASP.NET Core gRPC テンプレートとサンプルでは、既定で TLS を使用しています。 gRPC サーバーを起動しようとすると、次のエラー メッセージが表示されます。
Unable to bind to https://localhost:5001 on the IPv4 loopback interface:'HTTP/2 over TLS is not supported on macOS due to missing ALPN support.'. (IPv4 ループバック インターフェイスで https://localhost:5001 にバインドできません。'HTTP/2 over TLS は ALPN サポートがないため、macOS でサポートされていません。')
.NET 7 以前でこの問題を回避するには、TLS を "使わずに" HTTP/2 を使用するように Kestrel と gRPC クライアントを構成します。 これは開発時にのみ実行してください。 TLS を使用しないと、gRPC メッセージが暗号化されずに送信されます。
Kestrel では、Program.cs
に TLS を使用せずに HTTP/2 エンドポイントを構成する必要があります。
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>();
});
HTTP/2 エンドポイントが TLS を使用せずに構成されている場合、エンドポイントの ListenOptions.Protocol を HttpProtocols.Http2
に設定する必要があります。 HTTP/2 のネゴシエートに TLS が必要であるため、HttpProtocols.Http1AndHttp2
は使用できません。 TLS を使用しない場合、エンドポイントへのすべての接続が既定で HTTP/1.1 に設定され、gRPC の呼び出しが失敗します。
GRPC クライアントでも、TLS を使用しないように構成する必要があります。 詳細については、「.NET Core クライアントで安全でない gRPC サービスを呼び出す」を参照してください。
警告
TLS を使用しない HTTP/2 は、アプリの開発時にのみ使用してください。 実稼働アプリでは、常にトランスポート セキュリティを使用する必要があります。 詳細については、 gRPC for ASP.NET Core のセキュリティの考慮事項 に関するページを参照してください。
gRPC C# アセットが .proto
ファイルから生成されたコードでない
具象クライアントとサービス基本クラスの gRPC コード生成には、protobuf ファイルとツールをプロジェクトから参照する必要があります。 次のものを含める必要があります。
<Protobuf>
項目グループで使用する.proto
ファイル。 インポートされた.proto
ファイルをプロジェクトで参照する必要があります。- gRPC ツール パッケージ Grpc.Tools へのパッケージ参照。
gRPC C# アセットの生成の詳細については、「C# を使用した gRPC サービス」を参照してください。
gRPC サービスをホストしている ASP.NET Core Web アプリには、生成されたサービス基本クラスのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
gRPC 呼び出しを行う gRPC クライアント アプリでは、生成された具象クライアントのみが必要です。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
WPF プロジェクトで .proto
ファイルから gRPC C# アセットを生成できない
WPF プロジェクトには、gRPC コードの生成が正常に機能しなくなる既知の問題があります。 WPF プロジェクトで Grpc.Tools
と .proto
ファイルを参照して生成された gRPC 型は、使用すると、コンパイル エラーが発生します。
エラー CS0246:型または名前空間の名前 'tMyGrpcServices' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)
この問題は次の方法で回避できます。
- 新しい .NET Core クラス ライブラリ プロジェクトを作成します。
- 新しいプロジェクトで、参照を追加して、
.proto
ファイルからの C# コード生成を有効にします。- 次のパッケージ参照を追加します。
<Protobuf>
項目グループに.proto
ファイルを追加します。
- WPF アプリケーションで、新しいプロジェクトに参照を追加します。
WPF アプリケーションでは、新しいクラス ライブラリ プロジェクトから、gRPC によって生成された型を使用できます。
サブディレクトリでホストされている gRPC サービスの呼び出し
警告
多くのサードパーティ製 gRPC ツールでは、サブディレクトリでホストされているサービスはサポートされていません。 ルート ディレクトリとして gRPC をホストする方法を見つけることを検討してください。
gRPC 呼び出しを行うときに、gRPC チャネルのアドレスのパス コンポーネントは無視されます。 たとえば、GrpcChannel.ForAddress("https://localhost:5001/ignored_path")
では、サービスの gRPC 呼び出しをルーティングするときに ignored_path
は使用されません。
このアドレス パスが無視されるのは、gRPC には標準化された規範的なアドレス構造があるためです。 gRPC アドレスは、パッケージ名、サービス名、およびメソッド名を組み合わせたものです (https://localhost:5001/PackageName.ServiceName/MethodName
)。
アプリで gRPC 呼び出しのパスを含める必要があるシナリオがいくつかあります。 たとえば、ASP.NET Core gRPC アプリが IIS ディレクトリでホストされていて、このディレクトリを要求に含める必要がある場合などです。 パスが必要な場合は、下のように指定されたカスタム SubdirectoryHandler
を使用して、gRPC 呼び出しに追加できます。
/// <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 チャネルが作成されるときに使用されます。
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" });
上記のコードでは次の操作が行われます。
- パス
/MyApp
を使用してSubdirectoryHandler
を作成します。 SubdirectoryHandler
を使用するようにチャネルを構成します。SayHelloAsync
を使用して gRPC サービスを呼び出します。 gRPC 呼び出しがhttps://localhost:5001/MyApp/greet.Greeter/SayHello
に送信されます。
クライアント ファクトリは、SubdirectoryHandler
で AddHttpMessageHandler を使用して構成することもできます。