ShowProgramCode

2022年8月5日 星期五

C# 連結Golang的Grpc Server

Grpc Client專案要如何設定,請參考之前的文章
這裡主要說明的是如何使用C# .NetCore作為Client連結Golang的Grpc Server。

Golang Grpc Server proto調整

  1. syntax = "proto3"; // 定義要使用的 protocol buffer 版本
  2.  
  3. option csharp_namespace = "GrpcTestApi";
  4.  
  5. package grpcServer; // for name space
  6. //option go_package = "./;grpcServer"; // generated code 的 full Go import path
  7.  
  8. message SumRequest {
  9. repeated int64 input = 1 [packed=true];
  10. }
  11.  
  12. message SumResponse {
  13. int64 result = 1;
  14. }
  15.  
  16. message RemainderRequest{
  17. int64 a = 1;
  18. int64 b = 2;
  19. }
  20.  
  21. message RemainderResponse {
  22. int64 result = 1;
  23. }
  24.  
  25. service grpcService {
  26. rpc Sum(SumRequest) returns (SumResponse) {};
  27. rpc Remainder(RemainderRequest) returns (RemainderResponse) {};
  28. }

連線Grpc Client Help物件

  1. public class GrpcServerConnectHelp
  2. {
  3. private string serverUrl;
  4. private grpcService.grpcServiceClient client;
  5.  
  6. public string ServerUrl { get { return serverUrl; } }
  7.  
  8. public GrpcServerConnectHelp()
  9. {
  10. Init(System.Configuration.ConfigurationManager.AppSettings.Get("GrpcServerUrl"));
  11. }
  12.  
  13. public void Init(string url = null)
  14. {
  15. if (string.IsNullOrEmpty(url))
  16. return;
  17.  
  18. serverUrl = url;
  19. //.NetCore 3.*版本必須加入此行,否則會錯誤。
  20. AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
  21. var channel = GrpcChannel.ForAddress(serverUrl);
  22. client = new grpcService.grpcServiceClient(channel);
  23. }
  24.  
  25. public string CommonApi(string method, string input)
  26. {
  27. string resp = "查無此函式";
  28.  
  29. if (method.Equals("Sum"))
  30. {
  31. return Sum(input);
  32. }
  33.  
  34. if(method.Equals("Remainder"))
  35. {
  36. return Remainder(input);
  37. }
  38.  
  39. return resp;
  40. }
  41.  
  42. private string Sum(string input)
  43. {
  44. dynamic dyn = JsonConvert.DeserializeObject(input);
  45. SumRequest request = new SumRequest();
  46.  
  47. foreach(var value in dyn.Input)
  48. {
  49. long temp = Convert.ToInt64(value);
  50. request.Input.Add(temp);
  51. }
  52. var reply = client.Sum(request);
  53. return reply.Result.ToString();
  54. }
  55.  
  56. private string Remainder(string input)
  57. {
  58. dynamic dyn = JsonConvert.DeserializeObject(input);
  59. RemainderRequest request = new RemainderRequest();
  60. request.A = dyn.A;
  61. request.B = dyn.B;
  62.  
  63. var reply = client.Remainder(request);
  64. return reply.Result.ToString();
  65. }
  66. }

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

重點在於.Net Core 3.*的版本再傳入URL前,必須加入上面的語法,否則會產生錯誤

C# Grpc Server&Client範例

使用Grpc的預設專案,建立一個C#的GrpcServer+Client在同一個專案下。

 所以大致有以下三個動作:

  1. 建立範例Grpc Server專案
  2. 在同一個方案內建立Grpc Client專案
  3. 將共用的.proto檔案copy到Client中
  4. 測試專案

建立Grpc Server

  • 建立Grpc服務專案
  • 設定專案名稱
  • 選擇 .Net Core 3.1版本
  • Server的方案總管畫面
  • 更名Server專案名稱
  • 更改資料夾名稱
  • 編輯方案檔
  • 改寫Server專案路徑
GrpcDemo\Grpc.Server.csproj => Grpc.Server\Grpc.Server.cspro
  • 加入第三方套件參考
Server設定完成,執行沒有問題。

建立Grpc Client

  • 在同一方案中加入新專案(Client)
  • 專案類型選擇主控台
  • 設定專案名稱
  • 同樣選擇 .Net Core 3.1版本
  • 專案建置完成的方案總管截圖
  • 將Proto檔Copy到此
  • 改寫 .proto檔案內容
Server端:改寫option內容
GrpcDemo => Grpc.Server
Server端:加入參考
Client端:改寫option內容
GrpcDemo => Grpc.Client
  • 調整Grpc.Client.csproj
  • 重建方案
  • 修改Client程式碼
  1. static async Task Main(string[] args)
  2. {
  3. await Task.Delay(3000);
  4. using var channel = GrpcChannel.ForAddress("https://localhost:5001");
  5. var client = new Greeter.GreeterClient(channel);
  6. Console.WriteLine("請輸入你的名字...");
  7. string name = Console.ReadLine();
  8. var reply = client.SayHello(new HelloRequest { Name = name });
  9. Console.WriteLine("問候語 : " + reply.Message);
  10. await channel.ShutdownAsync();
  11. Console.WriteLine("按任何一個鍵退出...");
  12. Console.ReadKey();
  13. }
  • 從方案屬性調整起始專案
  • 開始測試
測試成功!!!