C#(.Net 6)でgRPCサーバー on Mac
作成日:
.Net 6 も出たし……と思い、C# で gRPC のサンプルをMacで動かそうとしたらエラーで落ちてちょっと戸惑ったので、手順を書いておきます。
- ASP.NET Core で .NET Core gRPC のクライアントとサーバーを作成する | Microsoft Docs
- ASP.NET Core で gRPCurl を使用して gRPC サービスをテストする | Microsoft Docs
手順
テンプレートからプロジェクトを作る
gRPCのテンプレからプロジェクトを作ります。
$ dotnet new grpc -o GrpcGreeter
実行(落ちる)
普通に実行します。するとMacでは落ちます。
$ cd GrpcGreeter
$ dotnet run
ビルドしています...
Unhandled exception. System.IO.IOException: Failed to bind to address https://localhost:7229.
---> System.AggregateException: One or more errors occurred. (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.) (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.)
対処:TLSを使わない
落ちる理由はエラーメッセージにも チュートリアル にも書いてあって、Macや古いWindowsではHTTP2 on TLSがサポートされていないからです。よってTLSを使わないようにすれば解決です。
で、.NET Core での gRPC のトラブルシューティング | Microsoft DocsにはProgram.csに書き足せという旨が書かれているわけですが、これが正直よくわからない。たぶんテンプレートの形式が変わってしまったのだろうなと思われます。
というわけで、次のようにして雑に解決しました。
Properties/launchSettings.json には
{
"profiles": {
"GrpcGreeter": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5142;https://localhost:7229",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
とありますが、これの applicationUrl
からhttpsのほうのURLを削り、
{
"profiles": {
"GrpcGreeter": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5142",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
として保存します。
実行
これで実行できます。
$ dotnet run
ビルドしています...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5142
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: /Users/suzusime/sandbox/GrpcGreeter/
grpcurlでテスト
これでサーバーが立つことがわかったので、grpcurlでAPIを叩いてみます。
reflectionを追加
grpcurlで叩くにはサーバーにreflection機能を追加する必要があるので、追加します(Goでやったときは不要だった気がするので本当は不要なのかも)。
まずは
$ dotnet add package Grpc.AspNetCore.Server.Reflection --version 2.40.0
でプロジェクトを追加します。
次に、Program.cs
を
using GrpcGreeter.Services;
var builder = WebApplication.CreateBuilder(args);
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddGrpcReflection(); // 追加
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.MapGrpcReflectionService(); // 追加
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run();
のように編集します。
grpcurlのインストール
homebrewで入ります。
$ brew install grpcurl
grpcurlで叩く
サーバーを立てます。
$ dotnet run
別のコンソールを開いてgrpcurlでサーバーを叩きましょう。まずは describe でAPIの使い方を調べてみます。
# 機能の一覧を出す
$ grpcurl -plaintext localhost:5142 describe
greet.Greeter is a service:
service Greeter {
rpc SayHello ( .greet.HelloRequest ) returns ( .greet.HelloReply );
}
grpc.reflection.v1alpha.ServerReflection is a service:
service ServerReflection {
rpc ServerReflectionInfo ( stream .grpc.reflection.v1alpha.ServerReflectionRequest ) returns ( stream .grpc.reflection.v1alpha.ServerReflectionResponse );
}
# 型の詳細を見る
$ grpcurl -plaintext localhost:5142 describe greet.HelloRequest
greet.HelloRequest is a message:
message HelloRequest {
string name = 1;
}
これでAPIの叩き方がわかったので、リクエストを送ってみます。
$ grpcurl -plaintext -d '{ "name": "世界" }' localhost:5142 greet.Greeter/SayHello
{
"message": "Hello 世界"
}
gRPCのサーバーが動いていることが確かめられました。
その他
- protobufのパスは GrpcGreeter.csproj で指定できるようになっています。protobufを変更しても、dotnet runしたときにいいかんじにC#のファイルも生成してくれるようです。
- サーバーの実装は Services/GreeterService.cs にあります(見れば分かりますが)。Greeter.GreeterBaseという自動生成される基底クラスを継承してオーバーライドしていく方式みたいです。
所感
テンプレに従うだけで動かせるので、とりあえずgRPCを試してみたいという需要ならGoでやる以上に楽ですね。
あと、Visual Studio for Mac 2022 Previewも入れてみたのですが、重くて正直微妙でした。VS Codeの出来が良すぎる……。