gRPC入門

by vivid 22. 一月 2020 03:03

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:
N200121502
出刊日期: 2020/1/22

gRPC是一個現代化、開放源碼、高效能的RPC框架 (Framework),可在任何平台上執行,用於遠端程序呼叫(Remote Procedure Calls),很適合分散運算,讓行動裝置應用程式、瀏覽器與後端的服務連結在一起。在這一篇文章之中,我們將介紹在ASP.NET Core設計gRPC服務(Service)以及gRPC用戶端(Client)程式,以了解其基本運作。

什麼是gRPC?

gRPC的特色:

  • 服務定義方式很簡單:使用Protocol Buffers格式定義,它是由Google推出的一種語言中立、平台中立的資料結構序列化協定,比起現下流行的JSON、XML資料格式還要精簡、快速、簡單。Protocol Buffer支援多種程式語言,例如C#、C++、Dart、Go、Java、Node、Objective-C、PHP、Python、Ruby...等等。
  • 安裝簡單,只需一行指令,也很容易延展。
  • 支援多種程式語言與平台。
  • 以HTTP/2為基礎,支援雙向串流(Bi-directional streaming)與驗證。

由於這些優點,gRPC很適合應用在輕量的微服務(microservices),或需要使用多種語言開發的系統,以及點對點(Point-to-point)即時串流服務。

建立ASP.NET Core gRPC伺服器專案

.NET Core 3.x版已經內建了gRPC,當你安裝Visual Studio 2019時,也會順便幫你安裝.NET Core,以下說明利用Visual Studio 2019建立ASP.NET Core gRPC伺服器專案的步驟。從Visual Studio開發工具「File」-「New」-「Project」項目,在「Create a New Project」對話盒中,選取「C#」程式語言,選取「gRPC Service」。請參考下圖所示:

clip_image002

圖 1:建立ASP.NET Core gRPC伺服器專案。

在出現的對話盒中,設定專案名稱為「MyGrpcService.」,設定專案存放路徑,然後按下「Create」鍵,請參考下圖所示:

clip_image004

圖 2:設定專案名稱與專案存放路徑。

在下一個畫面,選取「gRPC Service」項目,然後按下「Create」鍵,請參考下圖所示:

clip_image006

圖 3:使用「gRPC Service」範本建立專案。

gRPC使用合約優先(contract-first)原則來進行開發,服務(Service)與訊息(Message)定義在一個附檔名為「proto」的檔案之中。

首先從「Solution Explorer」視窗 -「「專案\protos」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」,在「Add New Item」對話盒中,選取「ASP.NET Core」-「General」分類下的「Protocol Buffer File(通訊協定緩衝區檔案)」,命名為「opera.proto」檔案,請參考下圖所示:

clip_image008

圖 4:加入通訊協定緩衝區檔案。

使用「opera.proto」通訊協定緩衝區檔案定義服務的內容如下,詳細的格式說明,可以參考官網文件,網址在:「https://developers.google.com/protocol-buffers/docs/overview」。

opera.proto

syntax = "proto3";
import "google/protobuf/empty.proto";
option csharp_namespace = "MyGrpcService.Operas";
package operas;

service Opera {
  rpc GetOpera (OperaRequest) returns (OperaReply);
  rpc GetOperaList (google.protobuf.Empty) returns (stream OperaReply);
}

message OperaRequest {
  int32 opera_id = 1;
}

message OperaReply {
  int32 opera_id = 1;
  string title = 2;
  int32 year = 3;
  string composer = 4;
}

 

根據Protocol Buffers官網(https://developers.google.com/protocol-buffers/docs/style)建議,通訊協定緩衝區檔案:

  • proto檔案一列儘量在80個字以內。
  • 使用兩個空白縮排。
  • package的名稱應該全部使用英文小寫,且要對應到資料夾名稱。
  • message名稱(message name)應該使用CamelCase命名法,例如 :「OperaRequest」
  • 欄位名(field name)稱應該以底線做區隔,例如 :「opera_id」。
  • Service名稱與RPC方法名稱都使用CamelCase命名法。

「opera.proto」通訊協定緩衝區檔案定義一個「Opera」gRPC服務,並且用來產生Server Stub相關類別,重點如下:

  • 「syntax」指明「Protocol Buffers」版本。
  • 「csharp_namespace」:動態產生的類別所在的命名空間。
  • 「package」指定套件名稱。
  • 「service」定義服務名稱,例如「Opera」。
  • 「rpc」定義一個RPC方法(Method)。
  • 「message」定義訊息格式。
  • 訊息中的每個欄位都指定一個唯一的數字,這些數字用來識別二進位格式訊息中的欄位,數字由1開始。
  • 「GetOperaList」方法接收空白的請求訊息(google.protobuf.Empty),並使用「stream」關鍵字,表示要回傳伺服端串流(Server Streaming),未來用戶端可以送出一個請求,取回訊息串流,其中包含多個項目的資料,不是只包含一個訊息。gRPC能夠確保用戶端接收訊息的順序與伺服端傳送的訊息一致。

在Visual Studio 2019的「Solution Explorer」視窗,選取「opera.proto」通訊協定緩衝區檔案,利用屬性(Properties)視窗,設定「Build Action」為「Protobuf compiler」,以及設定「gRPC Stub Classes」為「Server only」,請參考下圖所示:

clip_image010

圖 5:設定通訊協定緩衝區檔案「gRPC Stub Classes」為「Server only」。

選取Visual Studio 2019開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。專案編譯時,預設會在「專案名稱\obj\Debug\netcoreapp3.1」資料夾下,產生兩個檔案「Opera.cs」與「OperaGrpc.cs」裏頭包含工具動態產生的「Server Stub」類別,用來讀寫訊息(message)。

設計ASP.NET Core gRPC服務

有了「proto」定義檔之後,可以根據產生的「Server Stub」類別來建立gRPC服務。

從「Solution Explorer」視窗 -「「專案\Services」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」,請參考下圖所示:

clip_image012

圖 6:加入服務類別。

在「Add New Item」對話盒中,選取「ASP.NET Core」-「Code」分類下的「Class」,命名為「OperaService.cs」檔案,請參考下圖所示:

clip_image014

圖 7:設定服務檔案名稱。

gRPC服務可以裝載在ASP.NET Core中執行,在「OperaService」類別中加入以下程式碼:

OperaService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using MyGrpcService.Operas;

namespace MyGrpcService.Services {
  public class OperaService : Opera.OperaBase {
    static List<OperaReply> list = new List<OperaReply> {
               new OperaReply
               {
                  OperaId = 1,
                   Title = "Cosi Fan Tutte",
                   Year = 1790,
                   Composer = "Wolfgang Amadeus Mozart",
               },
              new OperaReply
              {
                  OperaId = 2,
                  Title = "Rigoletto",
                  Year = 1851,
                  Composer = "Giuseppe Verdi",
              },
              new OperaReply
              {
                  OperaId = 3,
                  Title = "Nixon in China",
                  Year = 1987,
                  Composer = "John Adams"
              },
              new OperaReply
              {
                  OperaId = 4,
                  Title = "Wozzeck",
                  Year = 1922,
                  Composer = "Alban Berg"
              }
          };
    public override Task<OperaReply> GetOpera( OperaRequest request , ServerCallContext context ) {
      var o = list.Find( o => o.OperaId == request.OperaId );
      return Task.FromResult( o );
    }

    public override async Task GetOperaList( Empty request , IServerStreamWriter<OperaReply> responseStream , ServerCallContext context ) {
      foreach ( var o in list ) {
        await responseStream.WriteAsync( o );
      }
    }
  
  }
}

 

「OperaService」繼承「Opera.OperaBase」型別,此型別的定義是根據「proto」檔案的定義,自動產生的。

 

啟用服務

我們還需要在「Startup」類別啟用gRPC服務,修改「Configure」方法的程式碼:

Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyGrpcService.Services;

namespace MyGrpcService {
  public class Startup {
    public void ConfigureServices( IServiceCollection services ) {
      services.AddGrpc();
    }
    public void Configure( IApplicationBuilder app , IWebHostEnvironment env ) {
      if ( env.IsDevelopment() ) {
        app.UseDeveloperExceptionPage();
      }
      app.UseRouting();
      app.UseEndpoints( endpoints => {
        //endpoints.MapGrpcService<GreeterService>();
        endpoints.MapGrpcService<OperaService>();
        endpoints.MapGet( "/" , async context => {
          await context.Response.WriteAsync( "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909" );
        } );
      } );
    }
  }
}

叫用「AddGrpc」方法啟用gRPC服務。叫用「MapGrpcService」方法會自動將服務加入路由管線。在Visual Studio開發工具,按CTRL+F5執行,執行結果參考如下:

clip_image016

圖 8:執行服務。

設計gRPC 用戶端

完成gRPC服務的定義與服務程式碼之後,接著我們便可以在方案之中加入並設計gRPC用戶端程式。從「Solution Explorer」視窗 -「Solution...」項目上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Project」項目,從「Add a new project」對話盒中,選取「C#」-「Console App (.NET Core)」,請參考下圖所示:

clip_image018

圖 9:加入用戶端專案到方案。

設定專案名稱為「MygRPCClient.」,設定專案存放路徑,然後按下「Create」鍵,請參考下圖所示:

clip_image020

圖 10:設定用戶端專案名稱。

gRPC用戶端專案需要安裝以下套件來協助開發:

  • 「Grpc.Net.Client」:包含.NET Core用戶端。
  • 「Google.Protobuf」:提供C# protobuf訊息API。
  • 「Grpc.Tools」:工具程式。

從Visual Studio 2019開發工具「Solution Explorer」視窗選取用戶端專案「MygRPCClient.」,按滑鼠右鍵,從快捷選單選擇「Manage NuGet Packages」,開啟「NuGet Package Manager」對話盒,請參考下圖所示:

clip_image022

圖 11:安裝套件。

點選「Browse」項目,並在下方的文字方塊中輸入「Grpc.Net.Client」關鍵字搜尋套件,然後按右方「Install」按鈕進行安裝,請參考下圖所示:

clip_image024

圖 12:安裝「Grpc.Net.Client」套件。

重複上個步驟,安裝「Google.Protobuf」套件,請參考下圖所示:

clip_image026

圖 13:安裝「「Google.Protobuf」套件。

重複上個步驟,安裝「Grpc.Tools」套件,請參考下圖所示:

clip_image028

圖 14:安裝「Grpc.Tools」套件。

從「MyGrpcService」專案複製「opera.proto」檔案到「gRPC Client」專案的「Protos」資料夾,然後利用屬性(Properties)視窗將用戶端「opera.proto」通訊協定緩衝區檔案的「gRPC Stub Classes」屬性設定為「Client Only」,請參考下圖所示:

clip_image030

圖 15:設定用戶端「opera.proto」通訊協定緩衝區檔案的「gRPC Stub Classes」屬性為「Client Only」。

選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。專案編譯時,預設會在「專案名稱\obj\Debug\netcoreapp3.1」資料夾下,產生兩個檔案「Opera.cs」與「OperaGrpc.cs」裏頭包含工具動態產生的「Client Stub」類別,用來讀寫訊息(message)。

最後用戶端專案「Main」方法中加入以下程式碼來叫用服務:

Program.cs

 

using Grpc.Net.Client;
using MyGrpcService.Operas;
using System;
using System.Threading.Tasks;

namespace MygRPCClient {
  class Program {
    static async Task Main( string[] args ) {
      var channel = GrpcChannel.ForAddress( "https://localhost:5001" );
      var client = new Opera.OperaClient( channel );
      var reply = await client.GetOperaAsync(
                        new OperaRequest { OperaId = 1 } );

      Console.WriteLine(reply);
      Console.ReadKey();
    }
  }
}

 

在程式中使用「GrpcChannel.ForAddress」 建立一個跟遠端服務的連線,然後建立gRPC用戶端(Opera.OperaClient),叫用「GetOperaAsync」方法取回結果顯示在主控台。

測試

從「Solution Explorer」視窗 -「Solution...」項目上方,按滑鼠右鍵,從快捷選單選擇「Properties」項目,從對話盒中,選取「Multiple startup projects」,利用右方箭頭調整專案啟動順序,先執行服務,再執行用戶端專案,請參考下圖所示:

clip_image032

圖 16:設定專案啟動順序。

在Visual Studio 2019開發工具,按CTRL+F5執行,執行結果參考如下:

clip_image034

圖 17:範例執行結果。

修改「Main」方法程式碼,改叫用「GetOperaList」方法取回所有Opera資料:

Program.cs

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
using MyGrpcService.Operas;
using System;
using System.Threading.Tasks;

namespace MygRPCClient {
  class Program {
    static async Task Main( string[] args ) {
      var channel = GrpcChannel.ForAddress( "https://localhost:5001" );
      var client = new Opera.OperaClient( channel );
      var reply = client.GetOperaList( new Empty() );

      while ( await reply.ResponseStream.MoveNext() ) {
        Console.WriteLine( reply.ResponseStream.Current );
      }
      Console.ReadKey();
    }

  }
}

 

在Visual Studio 2019開發工具,按CTRL+F5執行,執行結果參考如下:

clip_image036

圖 18:取回資料串流。

Tags:

.NET Core | C# | .NET Magazine國際中文電子雜誌 | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List