接上篇.net Core集成Consul使用REST 接口简单调用之后,寻思着集成Gprc进行远程过程调用。RPC调用和REST调用的区别和优势在此不表。
目录
1. 服务端
2. 客户端
3. 服务既是客户端又是服务端如何配置
1. 服务端
新建 .net Core3.1项目,NuGet包分别引入,Consul、Google.Protobuf、Gprc.AspNetCore、Gprc.Tools、Gprc.Net.Client(既是客户端又是服务端需引入)
在项目根目录下,新建目录 Protos,新建一个 client.proto 文件,protobuf的文件格式详情 百度。。。
然后右键->编辑项目文件
需在配置文件中指明,该proto文件是 Server还是 Client
保存后,会在项目目录下的 obj->Debug->netcoreapp3.1->Protos 文件下 生成两个.cs 文件
新建 AppBuilderExtensions、HealthController 参照上一篇文章,唯一不同的地方在于,需禁用Consul 的 HTTPS检查,否则Consul的健康检查无法访问https服务,这点之前查阅资料说 Consul不支持https,有误,贴上代码
public static class AppBuilderExtensions
{
public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity)
{
var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔
HTTP = $"https://{serviceEntity.IP}:{serviceEntity.Port}/api/Health",//健康检查地址
TLSSkipVerify = true,// 禁用https检查
Timeout = TimeSpan.FromSeconds(5)
};
// Register service with consul
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = serviceEntity.ServiceName,
Address = serviceEntity.IP,
Port = serviceEntity.Port,
Tags = new[] { serviceEntity.ServiceName }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别
};
consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起)
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册
});
return app;
}
}
新建一个Service,实现Client.proto的方法
public class ClientService : Client.ClientBase
{
private readonly ILogger<ClientService> _logger;
public ClientService(ILogger<ClientService> logger)
{
_logger = logger;
}
public override Task<MessageResponse> FindDetail(MessageRequest request, ServerCallContext context)
{
return Task.FromResult(new MessageResponse
{
Message = "Hello this is GrpcClient" + request.Name,
Id = 2
}) ;
}
}
在Startup.cs中 将Grpc服务添加到终点路由
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// 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.AddControllers();
services.AddGrpc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Microsoft.Extensions.Hosting.IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
//app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
// 将Gprc服务添加到终结点路由
endpoints.MapGrpcService<ClientService>();
endpoints.MapControllers();
});
ServiceEntity serviceEntity = new ServiceEntity
{
IP = NetworkHelper.LocalIPAddress(),
Port = Convert.ToInt32(Configuration["Service:Port"]),
ServiceName = Configuration["Service:Name"],
ConsulIP = Configuration["Consul:IP"],
ConsulPort = Convert.ToInt32(Configuration["Consul:Port"])
};
app.RegisterConsul(lifetime, serviceEntity);
}
}
appsetting.json总需设置 kestrel 支持Http1和Http2,因为这样Consul健康检查也能通过,Grpc依赖http2的通讯
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Service": {
"Name": "server-grpc-client",
"Port": "5002"
},
"Consul": {
"IP": "192.168.3.154",
"Port": "8500"
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1AndHttp2"
}
}
}
运行项目,打开 Consul的页面,可以看到 该服务已注册到Consul上了。
2. 客户端
新建.net Core3.1 项目,引入 Consul、Google.Protobuf、Gprc.AspNetCore、Gprc.Tools、Gprc.Net.Client
在项目根目录下新建 Protos文件夹,把刚刚生成的 client.proto拷贝进来,右键编辑项目文件,把GprcServices写为 Client
新建一个Controller,实现服务的调用方法,上代码,,,,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Consul;
using Grpc.Net.Client;
using Microsoft.AspNetCore.Mvc;
namespace GrpcService.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class HomeController : ControllerBase
{
public string Detail()
{
MessageResponse response = ClientClient.FindDetail("XXX");
return "Client 服务返回数据:" + response.Message;
}
}
public static class ClientClient
{
private static GrpcChannel _channel;
private static Client.ClientClient _client;
static ClientClient()
{
// Consul地址
string consulAddr = "http://192.168.3.154:8500";
// 调用的Gprc服务
string serverName = "server-grpc-client";
var consulClient = new ConsulClient(a => a.Address = new Uri(consulAddr));
var services = consulClient.Catalog.Service(serverName).Result.Response;
if (services != null && services.Any())
{
var service = services[0];
// 忽略无效证书-----仅在开发环境使用
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
_channel = GrpcChannel.ForAddress($"https://{service.ServiceAddress}:{service.ServicePort}", new GrpcChannelOptions { HttpClient = httpClient });
_client = new Client.ClientClient(_channel);
}
}
public static MessageResponse FindDetail(string name)
{
return _client.FindDetail(new MessageRequest { Name = name });
}
}
}
这里需要说明的是,开发环境中,由于没有证书,调用过程中会报SSL证书问题的错误,因此在此加上,代码来源参考:https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0&WT.mc_id=DT-MVP-5003133
打开浏览器,访问调用地址
RPC调用成功。
在RPC服务调用那里,还可以根据Consul返回的service,加上负载均衡,这样就可以实现一部分微服务。接下来尝试 SpringCloud 和.net Core在Consul下实现Grpc的相互调用。
3. 服务既是客户端又是服务端如何配置
写demo的时候思索了下,服务既是客户端又是服务端.proto文件该如何配置,查看网上的示例,GrpcServices 要么是Server要么是Client。Visual Studio 2019 中,右键 proto文件点击属性,选择 Client and Server
配置完毕之后发现项目文件中的 GrpcServices 为 Both
同一个Protobuf文件在项目中可以既是服务端又是客户端