前言:
Grpc 默认是 ProtoFirst 的, 即先写 proto 文件, 再生成代码, 需要人工维护 proto, 生成的代码也不友好, 所以出现了 Grpc CodeFirst, 下面来说说我们是怎么实现 Grpc CodeFirst
目录:
实现和 WCF 一样的 CodeFirst
(1). 实现 Grpc CodeFirst, 简化 WCF 一定要抽取接口的问题
(2). 通过代码生成 proto 和注释, 给第三方语言使用
(3). 实现 Grpc DashBoard, 用于 Http 远程调用和管理
(4). 实现服务注册与发现
(5). 实现分布式日志跟踪
(6). 日志监控等等
1. 要实现 CodeFirst 先要了解 ProtoFirst 生成的代码, 下面我截了部分生成代码
(1). 关键是这个 BindService, 用于把实现的 Grpc 方法绑定到 GrpcServiceDefinition
- public static partial class Greeter
- {
- static readonly string __ServiceName = "helloworld.Greeter";
- static readonly grpc::Marshaller<global::Helloworld.HelloRequest> __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Helloworld.HelloReply> __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom);
- static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
- grpc::MethodType.Unary,
- __ServiceName,
- "SayHello",
- __Marshaller_helloworld_HelloRequest,
- __Marshaller_helloworld_HelloReply);
- static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHelloStream = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
- grpc::MethodType.ClientStreaming,
- __ServiceName,
- "SayHelloStream",
- __Marshaller_helloworld_HelloRequest,
- __Marshaller_helloworld_HelloReply);
- /// <summary>Creates service definition that can be registered with a server</summary>
- /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
- public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl)
- {
- return grpc::ServerServiceDefinition.CreateBuilder()
- .AddMethod(__Method_SayHello, serviceImpl.SayHello)
- .AddMethod(__Method_SayHelloStream, serviceImpl.SayHelloStream).Build();
- }
- /// <summary>Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
- /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
- /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
- /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
- public static void BindService(grpc::ServiceBinderBase serviceBinder, GreeterBase serviceImpl)
- {
- serviceBinder.AddMethod(__Method_SayHello, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(serviceImpl.SayHello));
- serviceBinder.AddMethod(__Method_SayHelloStream, serviceImpl == null ? null : new grpc::ClientStreamingServerMethod<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(serviceImpl.SayHelloStream));
- }
- }
(2).__Marshaller_helloworld_HelloRequest 这个是实现 protobuffer 的序列化和反序列化的一个委托
服务的请求参数和返回参数, 我们使用 Protobuf.NET 来实现序列化和反序列化, 和 WCF 一样需要给类打上标签
- /// <summary>
- /// 加法请求参数
- /// </summary>
- [ProtoContract]
- public class AddRequest
- {
- /// <summary>
- /// 第一个数字
- /// </summary>
- [ProtoMember(1)]
- public int Num1 { get; set; }
- /// <summary>
- /// 第二个数字
- /// </summary>
- [ProtoMember(2)]
- public int Num2 { get; set; }
- }
2. 要实现 CodeFirst 需要实现这个 BindService, 把我们的 Grpc 方法添加到 ServerServiceDefinition
(1). 我们让 Grpc 服务实现 IGrpcService 空接口, 用于标识是 GrpcService
- /// <summary>
- /// MathGrpc
- /// </summary>
- public class MathGrpc : IGrpcService
- {
- /// <summary>
- /// 加法
- /// </summary>
- /// <param name="request"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public Task<IntMessage> Add(AddRequest request, ServerCallContext context)
- {
- var result = new IntMessage();
- result.Value = request.Num1 + request.Num2;
- return Task.FromResult(result);
- }
- }
(2). 获取实现了 IGrpcService 接口的类, 然后反射获取方法, 再添加到 ServerServiceDefinition 即可
- /// <summary>
- /// 注入 IGrpcService
- /// </summary>
- /// <param name="grpcServices"></param>
- /// <returns></returns>
- private ServerBuilder UseGrpcService(IEnumerable<IGrpcService> grpcServices)
- {
- var builder = ServerServiceDefinition.CreateBuilder();
- grpcServices.ToList().ForEach(grpc => GrpcMethodHelper.AutoRegisterMethod(grpc, builder));
- _serviceDefinitions.Add(builder.Build());
- return this;
- }
未完, 待续, 欢迎评论拍砖
这些功能早在 2018 年就已经实现并运行在生产, 感兴趣的同学可以去 GitHub 上查看, 你要的都有, 欢迎提 issue
来源: https://www.cnblogs.com/rabbityi/p/12593922.html