[ASP.NET Core] 初見gRPC

gRPC由Google發起的系統,基於HTTP/2協定傳輸,使用ProtocolButters為介面描述語言,在Microsoft Docs有一篇針對gRPC與HttpApi的比較表,接著加上Server端以及Client的使用方式

Server


Nuget

dotnet add package Grpc.AspNetCore

Startup

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>();
    });
}

建立資料夾 “Protos”,以及新增檔案 hello.proto

// hello.proto

// 使用proto3
syntax = "proto3";

// namespace
option csharp_namespace = "GrpcServiceSample.Core";

// package
package hello;

// 定義方法 request and response
service Hello {
  rpc HelloWorld (HelloWorldRequest) returns (HelloWorldResponse);
}

// 下面定義 dto
message HelloWorldRequest {
  string name = 1;
}

message HelloWorldResponse {
  string message = 1;
}

編譯後會在 “obj” 底下產生對應的程式碼

實作 gRPC 服務的邏輯

  • 可以從 ctor 注入服務
public class GreeterService : Hello.HelloBase
{
    private readonly ILogger<GreeterService> _logger;

    public GreeterService(ILogger<GreeterService> logger)
    {
        _logger = logger;
    }

    public override Task<HelloWorldResponse> HelloWorld(HelloWorldRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloWorldResponse()
        {
            Message = "Hello World! " + request.Name
        });
    }
}

Client


Nuget

dotnet add package Google.Protobuf
dotnet add package Grpc.Net.Client
dotnet add package Grpc.Tools

把 Server 內定義的 hello.proto 直接copy過去

調整一下 .csproj,主要要把 GrpcServices 改成 Client

<ItemGroup>
    <Protobuf Include="Protos\hello.proto" GrpcServices="Client" />
</ItemGroup>

編譯後也會在 obj 底下產生對應的程式碼

呼叫 gRPC 服務

[HttpGet]
public async Task<string> Get()
{
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Hello.HelloClient(channel);
    var response = await client.HelloWorldAsync(new HelloWorldRequest
    {
        Name = "Test"
    });

    return response.Message;
}

把Server跟Client都跑起來,理應可以正常呼叫服務

把 gRPC 服務透過DI注入


Nuget

dotnet add package Grpc.Net.ClientFactory

Startup

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddGrpcClient<Hello.HelloClient>(options =>
    {
        options.Address = new Uri("http://localhost:5000");
    });
}

使用端

private readonly Hello.HelloClient _client;

public WeatherForecastController(Hello.HelloClient client)
{
    _client = client;
}

[HttpGet]
public async Task<string> Get()
{
    var response = await _client.HelloWorldAsync(new HelloWorldRequest
    {
        Name = "Test"
    });

    return response.Message;
}

不支援 HTTP/2 的 Server


若執行端不支援 HTTP/2,運行 Server 端時會出現Exception,在 Microsoft Docs 有提供解決方案

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.

Server端

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureKestrel(options =>
                    {
                        options.ListenLocalhost(5000, o => o.Protocols = HttpProtocols.Http2);
                    });
                    webBuilder.UseStartup<Startup>();
                });
}

Client端則是在呼叫服務前加上

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

比較 gRPC 服務與 HTTP API

搭配 ASP.NET Core 的 gRPC 服務

針對 .NET Core 上的 gRPC 進行疑難排解

Sample Code