我们是怎么实现Grpc CodeFirst

  • 2020 年 3 月 30 日
  • 筆記

前言:

Grpc默认是ProtoFirst的,即先写 proto文件,再生成代码,需要人工维护proto,生成的代码也不友好,所以出现了Grpc CodeFirst,下面来说说我们是怎么实现Grpc CodeFirst

 

目录:

实现和WCF一样的CodeFirst

(1). 实现Grpc CodeFirst,  简化WCF一定要抽取接口的问题

(2). 通过代码生成proto和注释,给第三方语言使用

(3). 实现Grpc DashBoard,用于Http远程调用和管理

(4). 实现服务注册与发现

(5). 实现分布式日志跟踪

(6). 日志监控等等

 

 

我们是怎么实现Grpc CodeFirst

 

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