ASP.NET Core gRPC アプリでの gRPC-Web
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
作成者: James Newton-King
既存の ASP.NET Core の gRPC サービスを、gRPC-Web プロトコルを使用してブラウザー アプリから呼び出せるように構成する方法について説明します。 gRPC-Web を使用すると、ブラウザーの JavaScript および Blazor アプリで gRPC サービスを呼び出せます。 ブラウザーベースのアプリから HTTP/2 gRPC サービスを呼び出すことはできません。 ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。
既存の ASP.NET Core アプリに gRPC サービスを追加する手順については、「ASP.NET Core アプリに gRPC サービスを追加する」を参照してください。
gRPC プロジェクトを作成する手順については、ASP.NET Core での .NET Core gRPC のクライアントとサーバーの作成に関する記事を参照してください。
ASP.NET Core gRPC-Web と Envoy
gRPC-Web を ASP.NET Core アプリに追加する方法には、次の 2 つの選択肢があります。
- ASP.NET Core の gRPC HTTP/2 と共に、gRPC-Web をサポートします。 このオプションでは、
Grpc.AspNetCore.Web
パッケージによって提供されるミドルウェアを使用します。 - Envoy プロキシの gRPC-Web サポートを使用して、gRPC-Web を gRPC HTTP/2 に変換します。 変換された呼び出しが、ASP.NET Core アプリに転送されます。
それぞれの方法には、長所と短所があります。 アプリの環境で既にプロキシとして Envoy を使用している場合は、gRPC-Web サポートを提供するために Envoy を使用するのも、妥当かもしれません。 ASP.NET Core のみを必要とする gRPC-Web の基本的なソリューションについては、Grpc.AspNetCore.Web
を選択することをお勧めします。
ASP.NET Core での gRPC-Web の構成
ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。 gRPC-Web では、サービスを変更する必要はありません。 唯一の変更は、Program.cs
のミドルウェアの設定です。
ASP.NET Core gRPC サービスで gRPC-Web を有効にするには:
Grpc.AspNetCore.Web
パッケージへの参照を追加します。- アプリで gRPC-Web を使用するように構成するには、
UseGrpcWeb
とEnableGrpcWeb
をProgram.cs
に追加します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps using the gRPC-Web protocol");
app.Run();
上記のコードでは次の操作が行われます。
- GRPC-Web ミドルウェアの
UseGrpcWeb
を、ルーティングの後かつエンドポイントの前に追加します。 endpoints.MapGrpcService<GreeterService>()
メソッドで、EnableGrpcWeb
を使用して gRPC-Web をサポートすることを指定します。
または、gRPC-Web ミドルウェアを構成して、すべてのサービスで既定で gRPC-Web がサポートされ、EnableGrpcWeb
が不要になるようにすることもできます。 ミドルウェアを追加するときに new GrpcWebOptions { DefaultEnabled = true }
を指定します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps using the gRPC-Web protocol");
app.Run();
Note
.NET Core 3.x で HTTP.sys によりホストされている場合は、gRPC-Web が失敗する原因となる既知の問題があります。
HTTP.sys で gRPC-Web を動作させるための回避策は、「Grpc-web experimental and UseHttpSys()? (gRPC-Web の実験と UseHttpSys()?)」(grpc/grpc-dotnet #853) で確認できます。
gRPC-Web と CORS
ブラウザーのセキュリティにより、Web ページを提供したドメインと異なるドメインに対して、Web ページが要求を行うことはできません。 この制限は、ブラウザー アプリで gRPC-Web 呼び出しを行う場合に適用されます。 たとえば、https://www.contoso.com
によって提供されるブラウザー アプリでは、https://services.contoso.com
でホストされている gRPC-Web サービスの呼び出しがブロックされます。 この制限を緩和するには、クロスオリジン リソース共有 (CORS) を使用できます。
ブラウザー アプリでクロス オリジン gRPC-Web 呼び出しを行えるようにするには、ASP.NET Core で CORS を設定します。 組み込みの CORS サポートを使用し、WithExposedHeaders で gRPC 固有のヘッダーを公開します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
}));
var app = builder.Build();
app.UseGrpcWeb();
app.UseCors();
app.MapGrpcService<GreeterService>().EnableGrpcWeb()
.RequireCors("AllowAll");
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps using the gRPC-Web protocol");
app.Run();
上記のコードでは次の操作が行われます。
AddCors
を呼び出して CORS サービスを追加し、gRPC 固有のヘッダーを公開する CORS ポリシーを構成します。UseCors
を呼び出して、ルーティング構成の後、エンドポイント構成の前に CORS ミドルウェアを追加します。endpoints.MapGrpcService<GreeterService>()
メソッドがRequireCors
で CORS をサポートすることを指定します。
gRPC-Web とストリーミング
従来の HTTP/2 経由の gRPC では、クライアント、サーバー、双方向の各ストリーミングがサポートされています。 gRPC-Web では、ストリーミングのサポートが制限されています。
- gRPC-Web ブラウザー クライアントでは、クライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- gRPC-Web .NET クライアントでは、HTTP/1.1 経由のクライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- Azure App Service および IIS でホストされている ASP.NET Core gRPC サービスでは、双方向ストリーミングはサポートされていません。
gRPC-Web を使用するときは、単項メソッドとサーバー ストリーミング メソッドのみを使用することをお勧めします。
HTTP プロトコル
.NET SDK に含まれる ASP.NET Core gRPC サービス テンプレートを使うと、HTTP/2 専用に構成されたアプリを作成できます。 これは、アプリが従来の HTTP/2 経由の gRPC のみをサポートする場合に適した既定値となります。 一方、gRPC-Web は HTTP/1.1 と HTTP/2 の両方で動作します。 UWP や Unity などの一部のプラットフォームでは、HTTP/2 を使用できません。 すべてのクライアント アプリをサポートするには、HTTP/1.1 と HTTP/2 を有効にするようにサーバーを構成します。
appsettings.json
で既定のプロトコルを更新します。
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1AndHttp2"
}
}
}
または、起動コードで Kestrel エンドポイントを構成します。
同じポートで HTTP/1.1 と HTTP/2 を有効にするには、プロトコル ネゴシエーション用に TLS が必要です。 詳細については、ASP.NET Core gRPC のプロトコル ネゴシエーションに関する記事を参照してください。
ブラウザーから gRPC-Web を呼び出す
ブラウザー アプリでは gRPC-Web を使用して gRPC サービスを呼び出すことができます。 ブラウザーから gRPC-Web を使用して gRPC サービスを呼び出す場合、いくつかの要件と制限があります。
- サーバーには、gRPC-Web をサポートするための構成が含まれている必要があります。
- クライアント ストリーミングと双方向ストリーミングの呼び出しはサポートされていません。 サーバー ストリーミングはサポートされています。
- 別のドメインで gRPC サービスを呼び出すには、サーバー上に CORS の構成が必要です。
JavaScript gRPC-Web クライアント
JavaScript の gRPC-Web クライアントが存在します。 JavaScript から gRPC-Web を使用する方法については、gRPC-Web を使用した JavaScript クライアント コードの作成に関するページを参照してください。
.NET gRPC クライアントを使用して gRPC-Web を構成する
gRPC-Web 呼び出しを行うように .NET gRPC クライアントを構成できます。 これは、ブラウザーでホストされ、JavaScript コードの同じ HTTP 制限がある Blazor WebAssembly アプリに役立ちます。 .NET クライアントによる gRPC-Web の呼び出しは、HTTP/2 gRPC と同じです。 唯一の変更点は、チャネルの作成方法です。
gRPC-Web を使用するには:
Grpc.Net.Client.Web
パッケージへの参照を追加します。Grpc.Net.Client
パッケージへの参照がバージョン 2.29.0 以降であるようにします。GrpcWebHandler
を使用するようにチャネルを構成します。
var channel = GrpcChannel.ForAddress("https://localhost:53305", new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
上記のコードでは次の操作が行われます。
- gRPC-Web を使用するようにチャネルを構成します。
- クライアントを作成し、チャネルを使用して呼び出しを行います。
GrpcWebHandler
には次の構成オプションがあります。
- InnerHandler
InnerHandler
: gRPC HTTP 要求を行う基になるInnerHandler
(HttpClientHandler
など)。 - GrpcWebMode
GrpcWebMode
: gRPC HTTP 要求のGrpcWebMode
が、application/grpc-web
とapplication/grpc-web-text
のどちらであるかを指定する列挙型。GrpcWebMode.GrpcWeb
では、エンコードなしのコンテンツ送信が構成されます。 既定値です。GrpcWebMode.GrpcWebText
では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
- HttpVersion
HttpVersion
: 基になる gRPC HTTP 要求で HttpRequestMessage.VersionHttpRequestMessage.Version を設定するために使用される HTTP プロトコルのHttpVersion
。 gRPC-Web では特定のバージョンを必要とせず、指定しない限り、既定値はオーバーライドされません。
重要
生成された gRPC クライアントには、単項メソッドを呼び出すための同期メソッドと非同期メソッドがあります。 たとえば、SayHello
は同期であり、SayHelloAsync
は非同期です。 非同期メソッドは Blazor WebAssembly で常に必要となります。 Blazor WebAssembly アプリで同期メソッドを呼び出すと、アプリが応答しなくなります。
gRPC-Web で gRPC クライアント ファクトリを使用する
gRPC クライアント ファクトリを使用して、gRPC-Web と互換性のある .NET クライアントを作成します。
- 次のパッケージのプロジェクト ファイルにパッケージ参照を追加します。
- 汎用の
AddGrpcClient
拡張メソッドを使用して、依存関係の注入 (DI) に gRPC クライアントを登録します。 Blazor WebAssembly アプリでは、サービスはProgram.cs
で DI に登録されます。 - ConfigurePrimaryHttpMessageHandler 拡張メソッドを使用して
GrpcWebHandler
を構成します。
builder.Services
.AddGrpcClient<Greet.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
})
.ConfigurePrimaryHttpMessageHandler(
() => new GrpcWebHandler(new HttpClientHandler()));
詳細については、「.NET での gRPC クライアント ファクトリの統合」を参照してください。
その他の技術情報
既存の ASP.NET Core の gRPC サービスを、gRPC-Web プロトコルを使用してブラウザー アプリから呼び出せるように構成する方法について説明します。 gRPC-Web を使用すると、ブラウザーの JavaScript および Blazor アプリで gRPC サービスを呼び出せます。 ブラウザーベースのアプリから HTTP/2 gRPC サービスを呼び出すことはできません。 ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。
既存の ASP.NET Core アプリに gRPC サービスを追加する手順については、「ASP.NET Core アプリに gRPC サービスを追加する」を参照してください。
gRPC プロジェクトを作成する手順については、ASP.NET Core での .NET Core gRPC のクライアントとサーバーの作成に関する記事を参照してください。
ASP.NET Core gRPC-Web と Envoy
gRPC-Web を ASP.NET Core アプリに追加する方法には、次の 2 つの選択肢があります。
- ASP.NET Core の gRPC HTTP/2 と共に、gRPC-Web をサポートします。 このオプションでは、
Grpc.AspNetCore.Web
パッケージによって提供されるミドルウェアを使用します。 - Envoy プロキシの gRPC-Web サポートを使用して、gRPC-Web を gRPC HTTP/2 に変換します。 変換された呼び出しが、ASP.NET Core アプリに転送されます。
それぞれの方法には、長所と短所があります。 アプリの環境で既にプロキシとして Envoy を使用している場合は、gRPC-Web サポートを提供するために Envoy を使用するのも、妥当かもしれません。 ASP.NET Core のみを必要とする gRPC-Web の基本的なソリューションについては、Grpc.AspNetCore.Web
を選択することをお勧めします。
ASP.NET Core での gRPC-Web の構成
ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。 gRPC-Web では、サービスを変更する必要はありません。 唯一の変更は、Program.cs
のミドルウェアの設定です。
ASP.NET Core gRPC サービスで gRPC-Web を有効にするには:
Grpc.AspNetCore.Web
パッケージへの参照を追加します。- アプリで gRPC-Web を使用するように構成するには、
UseGrpcWeb
とEnableGrpcWeb
をProgram.cs
に追加します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps using the gRPC-Web protocol");
app.Run();
上記のコードでは次の操作が行われます。
- GRPC-Web ミドルウェアの
UseGrpcWeb
を、ルーティングの後かつエンドポイントの前に追加します。 endpoints.MapGrpcService<GreeterService>()
メソッドで、EnableGrpcWeb
を使用して gRPC-Web をサポートすることを指定します。
または、gRPC-Web ミドルウェアを構成して、すべてのサービスで既定で gRPC-Web がサポートされ、EnableGrpcWeb
が不要になるようにすることもできます。 ミドルウェアを追加するときに new GrpcWebOptions { DefaultEnabled = true }
を指定します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps using the gRPC-Web protocol");
app.Run();
Note
.NET Core 3.x で HTTP.sys によりホストされている場合は、gRPC-Web が失敗する原因となる既知の問題があります。
HTTP.sys で gRPC-Web を動作させるための回避策は、「Grpc-web experimental and UseHttpSys()? (gRPC-Web の実験と UseHttpSys()?)」(grpc/grpc-dotnet #853) で確認できます。
gRPC-Web と CORS
ブラウザーのセキュリティにより、Web ページを提供したドメインと異なるドメインに対して、Web ページが要求を行うことはできません。 この制限は、ブラウザー アプリで gRPC-Web 呼び出しを行う場合に適用されます。 たとえば、https://www.contoso.com
によって提供されるブラウザー アプリでは、https://services.contoso.com
でホストされている gRPC-Web サービスの呼び出しがブロックされます。 この制限を緩和するには、クロスオリジン リソース共有 (CORS) を使用できます。
ブラウザー アプリでクロス オリジン gRPC-Web 呼び出しを行えるようにするには、ASP.NET Core で CORS を設定します。 組み込みの CORS サポートを使用し、WithExposedHeaders で gRPC 固有のヘッダーを公開します。
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
}));
var app = builder.Build();
app.UseGrpcWeb();
app.UseCors();
app.MapGrpcService<GreeterService>().EnableGrpcWeb()
.RequireCors("AllowAll");
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps using the gRPC-Web protocol");
app.Run();
上記のコードでは次の操作が行われます。
AddCors
を呼び出して CORS サービスを追加し、gRPC 固有のヘッダーを公開する CORS ポリシーを構成します。UseCors
を呼び出して、ルーティング構成の後、エンドポイント構成の前に CORS ミドルウェアを追加します。endpoints.MapGrpcService<GreeterService>()
メソッドがRequireCors
で CORS をサポートすることを指定します。
gRPC-Web とストリーミング
従来の HTTP/2 経由の gRPC では、クライアント、サーバー、双方向の各ストリーミングがサポートされています。 gRPC-Web では、ストリーミングのサポートが制限されています。
- gRPC-Web ブラウザー クライアントでは、クライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- gRPC-Web .NET クライアントでは、HTTP/1.1 経由のクライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- Azure App Service および IIS でホストされている ASP.NET Core gRPC サービスでは、双方向ストリーミングはサポートされていません。
gRPC-Web を使用するときは、単項メソッドとサーバー ストリーミング メソッドのみを使用することをお勧めします。
HTTP プロトコル
.NET SDK に含まれる ASP.NET Core gRPC サービス テンプレートを使うと、HTTP/2 専用に構成されたアプリを作成できます。 これは、アプリが従来の HTTP/2 経由の gRPC のみをサポートする場合に適した既定値となります。 一方、gRPC-Web は HTTP/1.1 と HTTP/2 の両方で動作します。 UWP や Unity などの一部のプラットフォームでは、HTTP/2 を使用できません。 すべてのクライアント アプリをサポートするには、HTTP/1.1 と HTTP/2 を有効にするようにサーバーを構成します。
appsettings.json
で既定のプロトコルを更新します。
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1AndHttp2"
}
}
}
または、起動コードで Kestrel エンドポイントを構成します。
同じポートで HTTP/1.1 と HTTP/2 を有効にするには、プロトコル ネゴシエーション用に TLS が必要です。 詳細については、ASP.NET Core gRPC のプロトコル ネゴシエーションに関する記事を参照してください。
ブラウザーから gRPC-Web を呼び出す
ブラウザー アプリでは gRPC-Web を使用して gRPC サービスを呼び出すことができます。 ブラウザーから gRPC-Web を使用して gRPC サービスを呼び出す場合、いくつかの要件と制限があります。
- サーバーには、gRPC-Web をサポートするための構成が含まれている必要があります。
- クライアント ストリーミングと双方向ストリーミングの呼び出しはサポートされていません。 サーバー ストリーミングはサポートされています。
- 別のドメインで gRPC サービスを呼び出すには、サーバー上に CORS の構成が必要です。
JavaScript gRPC-Web クライアント
JavaScript の gRPC-Web クライアントが存在します。 JavaScript から gRPC-Web を使用する方法については、gRPC-Web を使用した JavaScript クライアント コードの作成に関するページを参照してください。
.NET gRPC クライアントを使用して gRPC-Web を構成する
gRPC-Web 呼び出しを行うように .NET gRPC クライアントを構成できます。 これは、ブラウザーでホストされ、JavaScript コードの同じ HTTP 制限がある Blazor WebAssembly アプリに役立ちます。 .NET クライアントによる gRPC-Web の呼び出しは、HTTP/2 gRPC と同じです。 唯一の変更点は、チャネルの作成方法です。
gRPC-Web を使用するには:
Grpc.Net.Client.Web
パッケージへの参照を追加します。Grpc.Net.Client
パッケージへの参照がバージョン 2.29.0 以降であるようにします。GrpcWebHandler
を使用するようにチャネルを構成します。
var channel = GrpcChannel.ForAddress("https://localhost:53305", new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
上記のコードでは次の操作が行われます。
- gRPC-Web を使用するようにチャネルを構成します。
- クライアントを作成し、チャネルを使用して呼び出しを行います。
GrpcWebHandler
には次の構成オプションがあります。
- InnerHandler
InnerHandler
: gRPC HTTP 要求を行う基になるInnerHandler
(HttpClientHandler
など)。 - GrpcWebMode
GrpcWebMode
: gRPC HTTP 要求のGrpcWebMode
が、application/grpc-web
とapplication/grpc-web-text
のどちらであるかを指定する列挙型。GrpcWebMode.GrpcWeb
では、エンコードなしのコンテンツ送信が構成されます。 既定値です。GrpcWebMode.GrpcWebText
では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
- HttpVersion
HttpVersion
: 基になる gRPC HTTP 要求で HttpRequestMessage.VersionHttpRequestMessage.Version を設定するために使用される HTTP プロトコルのHttpVersion
。 gRPC-Web では特定のバージョンを必要とせず、指定しない限り、既定値はオーバーライドされません。
重要
生成された gRPC クライアントには、単項メソッドを呼び出すための同期メソッドと非同期メソッドがあります。 たとえば、SayHello
は同期であり、SayHelloAsync
は非同期です。 非同期メソッドは Blazor WebAssembly で常に必要となります。 Blazor WebAssembly アプリで同期メソッドを呼び出すと、アプリが応答しなくなります。
gRPC-Web で gRPC クライアント ファクトリを使用する
gRPC クライアント ファクトリを使用して、gRPC-Web と互換性のある .NET クライアントを作成します。
- 次のパッケージのプロジェクト ファイルにパッケージ参照を追加します。
- 汎用の
AddGrpcClient
拡張メソッドを使用して、依存関係の注入 (DI) に gRPC クライアントを登録します。 Blazor WebAssembly アプリでは、サービスはProgram.cs
で DI に登録されます。 - ConfigurePrimaryHttpMessageHandler 拡張メソッドを使用して
GrpcWebHandler
を構成します。
builder.Services
.AddGrpcClient<Greet.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
})
.ConfigurePrimaryHttpMessageHandler(
() => new GrpcWebHandler(new HttpClientHandler()));
詳細については、「.NET での gRPC クライアント ファクトリの統合」を参照してください。
その他の技術情報
既存の ASP.NET Core の gRPC サービスを、gRPC-Web プロトコルを使用してブラウザー アプリから呼び出せるように構成する方法について説明します。 gRPC-Web を使用すると、ブラウザーの JavaScript および Blazor アプリで gRPC サービスを呼び出せます。 ブラウザーベースのアプリから HTTP/2 gRPC サービスを呼び出すことはできません。 ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。
既存の ASP.NET Core アプリに gRPC サービスを追加する手順については、「ASP.NET Core アプリに gRPC サービスを追加する」を参照してください。
gRPC プロジェクトを作成する手順については、ASP.NET Core での .NET Core gRPC のクライアントとサーバーの作成に関する記事を参照してください。
ASP.NET Core gRPC-Web と Envoy
gRPC-Web を ASP.NET Core アプリに追加する方法には、次の 2 つの選択肢があります。
- ASP.NET Core の gRPC HTTP/2 と共に、gRPC-Web をサポートします。 このオプションでは、
Grpc.AspNetCore.Web
パッケージによって提供されるミドルウェアを使用します。 - Envoy プロキシの gRPC-Web サポートを使用して、gRPC-Web を gRPC HTTP/2 に変換します。 変換された呼び出しが、ASP.NET Core アプリに転送されます。
それぞれの方法には、長所と短所があります。 アプリの環境で既にプロキシとして Envoy を使用している場合は、gRPC-Web サポートを提供するために Envoy を使用するのも、妥当かもしれません。 ASP.NET Core のみを必要とする gRPC-Web の基本的なソリューションについては、Grpc.AspNetCore.Web
を選択することをお勧めします。
ASP.NET Core での gRPC-Web の構成
ASP.NET Core でホストされている gRPC サービスは、HTTP/2 gRPC と共に gRPC-Web をサポートするように構成できます。 gRPC-Web では、サービスを変更する必要はありません。 唯一の変更点はスタートアップ構成です。
ASP.NET Core gRPC サービスで gRPC-Web を有効にするには:
Grpc.AspNetCore.Web
パッケージへの参照を追加します。- アプリで gRPC-Web を使用するように構成するには、
UseGrpcWeb
とEnableGrpcWeb
をStartup.cs
に追加します。
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseGrpcWeb(); // Must be added between UseRouting and UseEndpoints
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
});
}
上記のコードでは次の操作が行われます。
- GRPC-Web ミドルウェアの
UseGrpcWeb
を、ルーティングの後かつエンドポイントの前に追加します。 endpoints.MapGrpcService<GreeterService>()
メソッドで、EnableGrpcWeb
を使用して gRPC-Web をサポートすることを指定します。
または、gRPC-Web ミドルウェアを構成して、すべてのサービスで既定で gRPC-Web がサポートされ、EnableGrpcWeb
が不要になるようにすることもできます。 ミドルウェアを追加するときに new GrpcWebOptions { DefaultEnabled = true }
を指定します。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
}
Note
.NET Core 3.x で HTTP.sys によりホストされている場合は、gRPC-Web が失敗する原因となる既知の問題があります。
HTTP.sys で gRPC-Web を動作させるための回避策は、「Grpc-web experimental and UseHttpSys()? (gRPC-Web の実験と UseHttpSys()?)」(grpc/grpc-dotnet #853) で確認できます。
gRPC-Web と CORS
ブラウザーのセキュリティにより、Web ページを提供したドメインと異なるドメインに対して、Web ページが要求を行うことはできません。 この制限は、ブラウザー アプリで gRPC-Web 呼び出しを行う場合に適用されます。 たとえば、https://www.contoso.com
によって提供されるブラウザー アプリでは、https://services.contoso.com
でホストされている gRPC-Web サービスの呼び出しがブロックされます。 この制限を緩和するには、クロスオリジン リソース共有 (CORS) を使用できます。
ブラウザー アプリでクロス オリジン gRPC-Web 呼び出しを行えるようにするには、ASP.NET Core で CORS を設定します。 組み込みの CORS サポートを使用し、WithExposedHeaders で gRPC 固有のヘッダーを公開します。
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
}));
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseGrpcWeb();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb()
.RequireCors("AllowAll");
});
}
上記のコードでは次の操作が行われます。
AddCors
を呼び出して CORS サービスを追加し、gRPC 固有のヘッダーを公開する CORS ポリシーを構成します。UseCors
を呼び出して、ルーティング構成の後、エンドポイント構成の前に CORS ミドルウェアを追加します。endpoints.MapGrpcService<GreeterService>()
メソッドがRequireCors
で CORS をサポートすることを指定します。
gRPC-Web とストリーミング
従来の HTTP/2 経由の gRPC では、クライアント、サーバー、双方向の各ストリーミングがサポートされています。 gRPC-Web では、ストリーミングのサポートが制限されています。
- gRPC-Web ブラウザー クライアントでは、クライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- gRPC-Web .NET クライアントでは、HTTP/1.1 経由のクライアント ストリーミング メソッドと双方向ストリーミング メソッドの呼び出しはサポートされていません。
- Azure App Service および IIS でホストされている ASP.NET Core gRPC サービスでは、双方向ストリーミングはサポートされていません。
gRPC-Web を使用するときは、単項メソッドとサーバー ストリーミング メソッドのみを使用することをお勧めします。
HTTP プロトコル
.NET SDK に含まれる ASP.NET Core gRPC サービス テンプレートを使うと、HTTP/2 専用に構成されたアプリを作成できます。 これは、アプリが従来の HTTP/2 経由の gRPC のみをサポートする場合に適した既定値となります。 一方、gRPC-Web は HTTP/1.1 と HTTP/2 の両方で動作します。 UWP や Unity などの一部のプラットフォームでは、HTTP/2 を使用できません。 すべてのクライアント アプリをサポートするには、HTTP/1.1 と HTTP/2 を有効にするようにサーバーを構成します。
appsettings.json
で既定のプロトコルを更新します。
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1AndHttp2"
}
}
}
または、起動コードで Kestrel エンドポイントを構成します。
同じポートで HTTP/1.1 と HTTP/2 を有効にするには、プロトコル ネゴシエーション用に TLS が必要です。 詳細については、ASP.NET Core gRPC のプロトコル ネゴシエーションに関する記事を参照してください。
ブラウザーから gRPC-Web を呼び出す
ブラウザー アプリでは gRPC-Web を使用して gRPC サービスを呼び出すことができます。 ブラウザーから gRPC-Web を使用して gRPC サービスを呼び出す場合、いくつかの要件と制限があります。
- サーバーには、gRPC-Web をサポートするための構成が含まれている必要があります。
- クライアント ストリーミングと双方向ストリーミングの呼び出しはサポートされていません。 サーバー ストリーミングはサポートされています。
- 別のドメインで gRPC サービスを呼び出すには、サーバー上に CORS の構成が必要です。
JavaScript gRPC-Web クライアント
JavaScript の gRPC-Web クライアントが存在します。 JavaScript から gRPC-Web を使用する方法については、gRPC-Web を使用した JavaScript クライアント コードの作成に関するページを参照してください。
.NET gRPC クライアントを使用して gRPC-Web を構成する
gRPC-Web 呼び出しを行うように .NET gRPC クライアントを構成できます。 これは、ブラウザーでホストされ、JavaScript コードの同じ HTTP 制限がある Blazor WebAssembly アプリに役立ちます。 .NET クライアントによる gRPC-Web の呼び出しは、HTTP/2 gRPC と同じです。 唯一の変更点は、チャネルの作成方法です。
gRPC-Web を使用するには:
Grpc.Net.Client.Web
パッケージへの参照を追加します。Grpc.Net.Client
パッケージへの参照がバージョン 2.29.0 以降であるようにします。GrpcWebHandler
を使用するようにチャネルを構成します。
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });
上記のコードでは次の操作が行われます。
- gRPC-Web を使用するようにチャネルを構成します。
- クライアントを作成し、チャネルを使用して呼び出しを行います。
GrpcWebHandler
には次の構成オプションがあります。
- InnerHandler
InnerHandler
: gRPC HTTP 要求を行う基になるInnerHandler
(HttpClientHandler
など)。 - GrpcWebMode
GrpcWebMode
: gRPC HTTP 要求のGrpcWebMode
が、application/grpc-web
とapplication/grpc-web-text
のどちらであるかを指定する列挙型。GrpcWebMode.GrpcWeb
では、エンコードなしのコンテンツ送信が構成されます。 既定値です。GrpcWebMode.GrpcWebText
では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
- HttpVersion
HttpVersion
: 基になる gRPC HTTP 要求で HttpRequestMessage.VersionHttpRequestMessage.Version を設定するために使用される HTTP プロトコルのHttpVersion
。 gRPC-Web では特定のバージョンを必要とせず、指定しない限り、既定値はオーバーライドされません。
重要
生成された gRPC クライアントには、単項メソッドを呼び出すための同期メソッドと非同期メソッドがあります。 たとえば、SayHello
は同期であり、SayHelloAsync
は非同期です。 非同期メソッドは Blazor WebAssembly で常に必要となります。 Blazor WebAssembly アプリで同期メソッドを呼び出すと、アプリが応答しなくなります。
gRPC-Web で gRPC クライアント ファクトリを使用する
gRPC クライアント ファクトリを使用して、gRPC-Web と互換性のある .NET クライアントを作成します。
- 次のパッケージのプロジェクト ファイルにパッケージ参照を追加します。
- 汎用の
AddGrpcClient
拡張メソッドを使用して、依存関係の注入 (DI) に gRPC クライアントを登録します。 Blazor WebAssembly アプリでは、サービスはProgram.cs
で DI に登録されます。 - ConfigurePrimaryHttpMessageHandler 拡張メソッドを使用して
GrpcWebHandler
を構成します。
builder.Services
.AddGrpcClient<Greet.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
})
.ConfigurePrimaryHttpMessageHandler(
() => new GrpcWebHandler(new HttpClientHandler()));
詳細については、「.NET での gRPC クライアント ファクトリの統合」を参照してください。
その他の技術情報
ASP.NET Core