前言:
gRPC默認是ProtoFirst的,即先寫 proto文件,再生成代碼,需要人工維護proto,生成的代碼也不友好,所以出現了gRPC CodeFirst,下面來說說我們是怎么實現gRPC CodeFirst
目錄:
實現和WCF一樣的CodeFirst
(1). 實現gRPC CodeFirst, 簡化WCF一定要抽取接口的問題
(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