这里简单记录下如何为.NetCore3.1的WebAPI项目新增gRPC支持,.Net 5 6 7大体上也差不多是这个思路,应该比3.1要简单一些,就不多赘述了,有需要可以参照本文问问gpt就足以了。
首先nuget引用包 Grpc.AspNetCore ,注意如果是3.1版本需要2.56版本的,2.57开始仅支持.net 6 7 8版本,而.Net Core 2.1是不能使用gRPC的,因为2.1仅支持http1。
引用完nuget包后,修改Startup.cs,在 ConfigureServices 方法下新增 services.AddGrpc(),样例如下:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(_ => true) // =AllowAnyOrigin()
.AllowCredentials();
}
)
);
services.AddGrpc();
services.AddControllers(m =>
{
m.Filters.Add(typeof(GlobalFilter));
})
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddHttpClient();
}
然后在 Configure 方法下新增 endpoints.MapGrpcService<YourService>(); 注意这里的YourService是稍后所编写的适配器,样例如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseSwagger();
app.UseSwaggerUI();
app.ConsulRegister(Configuration);
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGrpcService<AdService>();
});
}
之后修改 Program.cs,在ConfigureWebHostDefaults中,新增如下:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostBuilderContext, configurationBuilder) =>
{
var env = EnvironmentForBusiness.GetEnvironmentValForBusiness();
configurationBuilder
.SetBasePath(hostBuilderContext.HostingEnvironment.ContentRootPath)
.AddJsonFile($"appsettings.{env}.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
.AddDefault();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
//webBuilder.UseUrls("http://*:8088");
webBuilder.ConfigureKestrel(options =>
{
options.Listen(System.Net.IPAddress.Any, 8088, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
});
options.Listen(System.Net.IPAddress.Any, 8089, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
});
这里Listen了两个端口,一个是8088,另一个是8089,因为gRPC要求必须是http2,所以单独一个8089端口作为gRPC的端口,并且设置为http2,8088作为原有的http webAPI的端口,使用了Http1AndHttp2,可能你要问了都是Http1AndHttp2了为什么8088不能作为http和gRPC共同的端口呢,我这里试验过是不行的,客户端调用gRPC时会报错http2解析错误,所以必须是独立出来两个端口才行。
然后就是编写proto文件了,这里不用多说,就是标准的gRPC的protoBuf,我这里简单截图一个我项目中的测试样例:

编写好后,双击项目的Connected Services:

然后新增服务引用,选择gRPC,文件选择刚刚写好的proto文件,并且设置为服务器类型:

然后保存,生成项目,这个时候就会根据你的proto文件生成代码了。
最后就是编写适配器,适配器里的代码基本和你原有的API的Controller一样,这个类型应该继承你proto里定义的服务,类型名称AdService实际上就是你之前在Startup里写的YourService,而Ad这个命名空间则是你在proto文件里定义的csharp_namespace,而Advertisement则是proto文件里定义的service,最后的AdvertisementBase则是自动生成的类型:

然后重写proto文件里定义的rpc方法,在前面的截图里,这个方法叫做 Get :

基于以上实现后,这个WebAPI项目就同时支持http和gRPC调用了。
附赠.Net调用gRPC的方式:
首先先起一个支持gRPC的.Net项目,把上面的proto文件copy到这个项目中,然后按照上面提到的方式,双击Connected Services添加服务引用,注意这里不再是服务器模式,要选择客户端模式。
最后编写如下代码:
public class ClientService
{
public void Test()
{
using (var channel = GrpcChannel.ForAddress("http://localhost:8089"))
{
var client = new Ad.Advertisement.AdvertisementClient(channel);
var r = client.Get(new Ad.GetRequest { BasicData = "999,0,2,0,0,822ca7b3261a0b2ec10c8cdabfb5a0ea,0", Country = "344", Lang = "zh-CN", Type = Ad.AdType.WikiRecommend, Ptn = Ad.VersionPattern.Default });
}
}
}
按照以上方式就可以成功获取到接口的返回值了。