接上篇.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(既是客户端又是服务端需引入)

.net core 2.1如何调试 .net core consul_.net

在项目根目录下,新建目录 Protos,新建一个 client.proto 文件,protobuf的文件格式详情  百度。。。

.net core 2.1如何调试 .net core consul_grpc_02

然后右键->编辑项目文件

.net core 2.1如何调试 .net core consul_.net core 2.1如何调试_03

需在配置文件中指明,该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上了。

.net core 2.1如何调试 .net core consul_.net core 2.1如何调试_04

2. 客户端

新建.net Core3.1 项目,引入 Consul、Google.Protobuf、Gprc.AspNetCore、Gprc.Tools、Gprc.Net.Client

在项目根目录下新建 Protos文件夹,把刚刚生成的 client.proto拷贝进来,右键编辑项目文件,把GprcServices写为 Client

.net core 2.1如何调试 .net core consul_.net_05

新建一个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

.net core 2.1如何调试 .net core consul_consul_06

打开浏览器,访问调用地址

.net core 2.1如何调试 .net core consul_服务端_07

RPC调用成功。

在RPC服务调用那里,还可以根据Consul返回的service,加上负载均衡,这样就可以实现一部分微服务。接下来尝试 SpringCloud 和.net Core在Consul下实现Grpc的相互调用。

 

3. 服务既是客户端又是服务端如何配置

写demo的时候思索了下,服务既是客户端又是服务端.proto文件该如何配置,查看网上的示例,GrpcServices 要么是Server要么是Client。Visual Studio 2019 中,右键 proto文件点击属性,选择 Client and Server

.net core 2.1如何调试 .net core consul_grpc_08

配置完毕之后发现项目文件中的 GrpcServices 为 Both

.net core 2.1如何调试 .net core consul_consul_09

    同一个Protobuf文件在项目中可以既是服务端又是客户端