ASP.NET Core gRPC アプリでの gRPC-Web

作成者: 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 を使用するように構成するには、UseGrpcWebEnableGrpcWebProgram.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 uisng the gRPC-Web protocal");

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 uisng the gRPC-Web protocal");

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 uisng the gRPC-Web protocal");

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 には次の構成オプションがあります。

  • InnerHandlerInnerHandler: gRPC HTTP 要求を行う基になる InnerHandler (HttpClientHandler など)。
  • GrpcWebModeGrpcWebMode: gRPC HTTP 要求の GrpcWebMode が、application/grpc-webapplication/grpc-web-text のどちらであるかを指定する列挙型。
    • GrpcWebMode.GrpcWeb では、エンコードなしのコンテンツ送信が構成されます。 既定値です。
    • GrpcWebMode.GrpcWebText では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
  • HttpVersionHttpVersion: 基になる 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 を使用するように構成するには、UseGrpcWebEnableGrpcWebProgram.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 uisng the gRPC-Web protocal");

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 uisng the gRPC-Web protocal");

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 uisng the gRPC-Web protocal");

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 には次の構成オプションがあります。

  • InnerHandlerInnerHandler: gRPC HTTP 要求を行う基になる InnerHandler (HttpClientHandler など)。
  • GrpcWebModeGrpcWebMode: gRPC HTTP 要求の GrpcWebMode が、application/grpc-webapplication/grpc-web-text のどちらであるかを指定する列挙型。
    • GrpcWebMode.GrpcWeb では、エンコードなしのコンテンツ送信が構成されます。 既定値です。
    • GrpcWebMode.GrpcWebText では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
  • HttpVersionHttpVersion: 基になる 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 を使用するように構成するには、UseGrpcWebEnableGrpcWebStartup.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 には次の構成オプションがあります。

  • InnerHandlerInnerHandler: gRPC HTTP 要求を行う基になる InnerHandler (HttpClientHandler など)。
  • GrpcWebModeGrpcWebMode: gRPC HTTP 要求の GrpcWebMode が、application/grpc-webapplication/grpc-web-text のどちらであるかを指定する列挙型。
    • GrpcWebMode.GrpcWeb では、エンコードなしのコンテンツ送信が構成されます。 既定値です。
    • GrpcWebMode.GrpcWebText では、base64 でエンコードされたコンテンツが構成されます。 ブラウザーでのサーバー ストリーム呼び出しに必要です。
  • HttpVersionHttpVersion: 基になる 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 クライアント ファクトリの統合」を参照してください。

その他の技術情報