Grpc系列(一):Net5使用Grpc
最近公司新專案選項覺得使用GRPC,因為之前沒怎麼接觸過,所以覺得研究記錄一下使用過程,話不多說,我們第一步先在專案裡配置一下。
新建AspNetCoreGrpc Api專案,Nuget安裝 Grpc.AspNetCore 包,Startup類裡新增gRPC services:
services.AddGrpc();
然後新增Protos資料夾和PB協議檔案HelloTest.proto:
syntax = "proto3"; option csharp_namespace = "AspNetCoregRpcService"; import "google/protobuf/empty.proto"; package HelloGrpcTest; //定義包名 //定義服務 //定義方法 service HelloTest{ rpc SayHello(SayHelloRequest) returns(SayHelloResult); } message SayHelloRequest{ string Name=1; } //定義返回值 message SayHelloResult{ string message=1; }
這裡添加了一個名為HelloTest的服務和名為SayHello的方法,有一個入參並且有一個返回類SayHelloResult,
然後我們需要在csproj 專案檔案裡,包含對 proto 檔案引用:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <Protobuf Include="Protos\HelloTest.proto" GrpcServices="Server" /> </ItemGroup> <ItemGroup> <PackageReference Include="Grpc.AspNetCore" Version="2.27.0" /> </ItemGroup> </Project>
然後我們新增服務的實現,新增Services資料夾和HelloTestService.cs實現類:
using AspNetCoregRpcService; using Grpc.Core; using System.Threading.Tasks; namespace AspNetCoreGrpc.Services { public class HelloTestService: HelloTest.HelloTestBase { public override Task<SayHelloResult> SayHello(SayHelloRequest request, ServerCallContext context) { var result = new SayHelloResult { Message = $"Hi,My name is {request.Name}!" }; return Task.FromResult(result); } } }
接著我們需要在Startup.cs的Configure方法裡配置Map:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<HelloTestService>(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync("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"); }); }); }
最後我們需要在appsettings.json配置使用HTTP2,因為GRPC使用HTTP2通訊:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "Kestrel": { "EndpointDefaults": { "Protocols": "Http2" } } }
到這裡GRPC服務端我們已經寫好並且能夠測試使用了,但是在實際生產中我們要測試一個方法或者介面通常是在swagger直接呼叫的,那麼是不是可以讓GRPC也支援swagger呢,這個也是可以的,但是我們需要了解到,swagger走的是HTTP呼叫,那就意味著我們需要對服務進行HTTP和GRPC兩種支援,所以這裡的解決方案是監聽兩個埠,分別支援HTTP和GRPC,我們需要接著做一點改動:
Nuget引入Microsoft.AspNetCore.Grpc.HttpApi、Microsoft.AspNetCore.Grpc.Swagger包,需要勾選預覽版,還沒發正式版,並替換Startup.cs裡的方法:
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddGrpcHttpApi(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "AspNetCoreGrpc.api", Version = "v1" }); }); services.AddGrpcSwagger(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AspNetCoreGrpc v1")); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<HelloTestService>(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync("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"); }); }); }
這裡我們需要因為兩個google的PB協議檔案,所以大家需要下載一下:
https://github.com/aspnet/AspLabs/blob/c1e59cacf7b9606650d6ec38e54fa3a82377f360/src/GrpcHttpApi/sample/Proto/google/api/http.proto
https://github.com/aspnet/AspLabs/blob/c1e59cacf7b9606650d6ec38e54fa3a82377f360/src/GrpcHttpApi/sample/Proto/google/api/annotations.proto
放到google/api資料夾下就可以:
同時我們需要修改我們的HelloTest.proto協議檔案配置路由:
syntax = "proto3"; option csharp_namespace = "AspNetCoregRpcService"; import "google/api/annotations.proto"; package HelloGrpcTest; //定義包名 //定義服務 //定義方法 service HelloTest{ rpc SayHello(SayHelloRequest) returns(SayHelloResult){ option (google.api.http) = { post: "/SayHello" body: "*" }; }; } message SayHelloRequest{ string Name=1; } //定義返回值 message SayHelloResult{ string message=1; }
最後也是最關鍵的一步,設定分別監聽HTTP1和HTTP2埠:
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Hosting; namespace AspNetCoreGrpc { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } // 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 public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls().UseKestrel((host, options) => { options.ListenAnyIP(50051, o => o.Protocols = HttpProtocols.Http2); options.ListenAnyIP(8081, o => o.Protocols = HttpProtocols.Http1); }); webBuilder.UseStartup<Startup>(); }); } }
然後我們再改一下launchSettings.json指定8081埠就可以運行了:
{ "profiles": { "AspNetCoreGrpc": { "commandName": "Project", "launchBrowser": false, "applicationUrl": "https://localhost:8081", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
啟動執行然後瀏覽器打到http://localhost:8081/swagger/index.html 看下:
看起來沒問題了,那麼客戶端該如何使用呢,只要把Protos檔案拷貝到客戶端專案裡就可以了,當然常用方法是釋出Nuget包。