我們是怎么實現gRPC CodeFirst


前言:

gRPC默認是ProtoFirst的,即先寫 proto文件,再生成代碼,需要人工維護proto,生成的代碼也不友好,所以出現了gRPC CodeFirst,下面來說說我們是怎么實現gRPC CodeFirst

 

目錄:

實現和WCF一樣的CodeFirst

(1). 實現gRPC CodeFirst,  簡化WCF一定要抽取接口的問題

(2). 通過代碼生成proto和注釋,給第三方語言使用

(3). 實現gRPC DashBoard,用於Http遠程調用和管理

(4). 實現gRPC scope注入的三種方式(asp.net core3.0 grpc默認是scope)

(5). 實現服務注冊與發現

(6). 實現分布式日志跟蹤

(7). 日志監控等等

 

 

我們是怎么實現gRPC CodeFirst

 

1.要實現CodeFirst先要了解ProtoFirst生成的代碼,下面我截了部分生成代碼

(1).關鍵是這個BindService,用於把實現的gRPC方法綁定到ServerServiceDefinition

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即可

這里調用了GrpcMethodHelper.AutoRegisterMethod()方法,這是通過反射自動注冊GrpcMethod的方法

        /// <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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM