GrpcをC#で実装するには


GrpcをC#で実装するには

必要なNuGetパッケージ
Google.Protobuf
→やれることは以下のURLを参照
https://kagasu.hatenablog.com/entry/2018/04/29/233407#1-NuGet%E3%81%8B%E3%82%89-GoogleProtobuf-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B
今回は作成したprotoファイルを使うことに使用

Grpc
→Grpcを使用するためのライブラリ

Grpc.Reflection
Grpc.Tools
→Grpcで使用するファイル等を自動生成してくれるライブラリ
ビルドを実行することで自動生成される

Grpc環境の作成については以下のURLを参照
https://qiita.com/muroon/items/4e12dde47b9e8b1e94d3

前準備が完了したら、Grpcの実装を行っていく。

1.protoファイルの作成
下記が書き方の一例

syntax = "proto3";

package Grpctst;

service GrpcTest{
    rpc TestRun (TestRequest) returns (TestResponse) {}
}

message TestRequest{
    string request = 1; 
}

message TestResponse {
    string response = 1;
}

上記のファイルの意味
syntax:決まり文句みたいなもの
package:対象のnamespaceみたいなもの
service サービス名:サービスの名前とメソッドの定義引数と戻りを定義できる。
message メッセージ名:引数や戻り値の情報を定義する箇所
        stringやintなどの型を定義する。
        1は割り当てているIDみたいなものである。
        複数記載することも可能。

2.protoファイルの作成が完了後は、クラスライブラリMicrosoft.NET.Sdkを作成する。
作成後はプロジェクトのソリューションの設定に以下を追加する。


3.追加後にビルドを実行する。
実行するとクラスファイルを自動生成してくれる。
Grpctst.cs
GrpctstGrpc.cs
が生成されていればOK(ファイル名はパッケージ名いよって異なる)
これでGrpc操作を行う環境設定については完了。

4.データ受信の方法
受信を行うために以下のファイルを作成する。
GrpcTestImpl.cs(protoファイルのメソッドを設定するクラス)
GrpcTestReceive.cs(Grpcとやりとりをするためのクラス)

GrpcTestImpl.cs

class GrpcTestImpl : GrpcTest.GrpcTestBase
{
public override Task TestRun(TestRequest request, ServerCallContext context)
{
return Task.FromResult(new TestResponse { Response = request.request });
}
}

上記はGrpcTest.GrpcTestBaseを継承しています。
GrpcTestBaseは自動生成されたGrpctstGrpc.csの中で実装されています。
TestRunメソッドをオーバーライドして処理を記載することができます。
今回はテストですので、受信してきたデータをreturnするだけの処理としています。

GrpcTestReceive.cs(ほとんど決まり文句)

public class GrpcTestReceive
{
  const int Port = 50051;

  public void Run()
  {
    Server server = new Server
    {
      Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
    };

  var grpcTest = GrpcTest
      .BindService(new GrpcTestImpl())
      .Intercept(new GrpcInterceptor());
  server.Services.Add(grpcTest);

  var reflectionService = ServerReflection
      .BindService(new ReflectionServiceImpl(GrpcTest.Descriptor))
      .Intercept(new GrpcInterceptor());
  server.Services.Add(reflectionService);

  server.Start();
}

public class GrpcInterceptor : Interceptor
{
  public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(
    IAsyncStreamReader<TRequest> requestStream
    , ServerCallContext context
    , ClientStreamingServerMethod<TRequest, TResponse> continuation
    )
  {
    return base.ClientStreamingServerHandler(requestStream, context, continuation);
  }

 public override Task DuplexStreamingServerHandler<TRequest, TResponse>(
    IAsyncStreamReader<TRequest> requestStream
    , IServerStreamWriter<TResponse> responseStream
    , ServerCallContext context
    , DuplexStreamingServerMethod<TRequest, TResponse> continuation
    )
  {
    return base.DuplexStreamingServerHandler(requestStream, responseStream, context, continuation);
  }

  public override Task ServerStreamingServerHandler<TRequest, TResponse>(
    TRequest request
    , IServerStreamWriter<TResponse> responseStream
    , ServerCallContext context
    , ServerStreamingServerMethod<TRequest, TResponse> continuation
    )
  {
    return base.ServerStreamingServerHandler(request, responseStream, context, continuation);
  }

  public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
    TRequest request
    , ServerCallContext context
    , UnaryServerMethod<TRequest, TResponse> continuation
    )
  {
    foreach (var header in context.RequestHeaders)
    {
      Console.WriteLine(header);
    }

    var tokenHeader = context.RequestHeaders.FirstOrDefault((entry) => entry.Key == "token");
    if (tokenHeader == null)
    {
      context.Status = new Status(StatusCode.Unauthenticated, "ヘッダーにトークン情報がありません.");
    }
    return base.UnaryServerHandler(request, context, continuation);
  }
}

5.各種クラスの設定が完了したら実装は完了です。
実装が完了したらテストを行ってみる。
テストを行うのに便利なcurlツールでgrpcurlというのがあるので、使用してみるといいかもしれません。
インストールから使い方については以下を参照。
https://qiita.com/yukina-ge/items/a84693f01f3f0edba482

grpccurlのコマンド一例
サービス一覧表示
grpcurl -plaintext localhost:50051 list

サービス内のメソッド一覧を表示
grpcurl -plaintext localhost:50051 list サービス一覧表示で取得した名称

サービス呼び出し
grpcurl -plaintext localhost:50051 サービス一覧表示で取得した名称/サービス内のメソッド名称