gRpc NET Core


NET Core下使用gRpc公開服務(SSL/TLS)

一、前言

 

      前一陣子關於.NET的各大公眾號都發表了關於gRpc的消息,而隨之而來的就是一波關於.NET Core下如何使用的教程,但是在這眾多的教程中基本都是泛泛而談,難以實際在實際環境中使用,而該篇教程以gRpc為主,但是使用了其SSL/TLS,這樣更加符合實際的生產使用,期間也會配套的講解Docker、openssl等。

 

二、服務端

 

a.准備工作

筆者的項目分為三個部分分別如下所示:

Sino.GrpcService.Host(控制台):宿主程序

Sino.GrpcService.Impl(類庫):實現協議

Sino.GrpcService.Protocol(類庫):生成協議

 

最終的項目如下圖所示:

 

每個項目的project.json如下所示:

  View Code

 

其中“buildOptions”和“publishOptions”中我們將后面我們需要的證書包含到輸出和發布中,其中我們還利用了“Configuration”相關組件去讀取配置信息。

 

Sino.GrpcService.Impl:

  View Code

 

其中我們安裝了“MongoDb.Driver”,為了能夠貼近真實的情況,筆者這里采用MongoDb作為數據源來提供數據,當然讀者為了能夠快速上手可以硬編碼一些數據。

 

Sino.GrpcService.Protocol:

  View Code

至此項目的初始化結束。

 

b.編寫協議

      首先我們打開Sino.GrpcService.Protocol項目,在其中新建一個msg.proto文件,打開msg.proto文件,我們將在其中編寫基於proto3語言的協議,以便后面自動生成到各語言,如果讀者需要更深入的學習可以打開該網站Proto3語言指南

這里我們定義我們當前使用的是proto3語言並且包名(生成為C#則為命名空間)為:

syntax = "proto3";
package Sino.GrpcService;

 

 

筆者為該服務定義了1個服務,且有4種方法:

復制代碼
service MsgService{
  rpc GetList(GetMsgListRequest) returns (GetMsgListReply){}
  rpc GetOne(GetMsgOneRequest) returns (GetMsgOneReply){}
  rpc Edit(EditMsgRequest) returns (EditMsgReply){}
  rpc Remove(RemoveMsgRequest) returns (RemoveMsgReply){}
}
復制代碼

 

 

對應到其中每個方法的接收參數和返回參數的定義如下:

  View Code

 

到這為止我們就完成了協議的編寫。

 

c.將協議生成為C#代碼

      相對於網站的很多關於C#使用gRpc的教程都是基於.NET項目框架下的,所以可以安裝gRpc.Tools,但是.NET Core安裝后是找不到工具的,所以讀者可以新建一個.NET項目安裝該類庫,然后將其中的工具復制到Sino.GrpcService.Protocol中,這里讀者需要根據你當前的系統去選擇,復制完成之后在該項目中新建一個名為“ProtocGenerate.cmd”的文件,在其中輸入以下指令:

protoc -I . --csharp_out . --grpc_out . --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe msg.proto

 

然后讀者直接雙擊運行,就會看到項目下生成了“Msg.cs”和“MsgGrpc.cs”兩個文件,這樣就完成了所有協議部分的工作了,最終的項目結構如下所示:

 

d.編寫實現代碼

      有了協議層之后我們就可以開始編寫實現了,因為筆者這里使用了MongoDb提供數據所以下文篇幅會較長。

 

首先打開Sino.GrpcService.Impl項目在其中新建Model文件,然后在該文件夾下新建MsgDM.cs文件,該文件主要是定義MongoDb存儲的數據結構,具體內容如下所示:

  View Code

 

 

緊接着我們新建Repositories文件夾,在其中新建四個文件分別為“IDataContext.cs”、“DataContext.cs”、“IMsgRepository.cs”和“MsgRepository.cs”。打開IDataContext.cs文件在其中編寫如下內容:

復制代碼
    /// <summary>
    /// 數據庫上下文
    /// </summary>
    public interface IDataContext
    {
        IMongoDatabase Database { get; set; }
    }
復制代碼

 

 

打開DataContext.cs文件進行數據庫初始化相關工作:

復制代碼
    public class DataContext : IDataContext
    {
        public IMongoDatabase Database { get; set; }

        public DataContext(IConfigurationRoot config)
        {
            var client = new MongoClient(config.GetConnectionString("mongodb"));
            Database = client.GetDatabase("aSQ0cWkEshl8NiVn");
        }
    }
復制代碼

 

 

打開IMsgRepository.cs,我們需要在其中定義倉儲提供的操作:

復制代碼
/// <summary>
    /// 消息倉儲
    /// </summary>
    public interface IMsgRepository
    {
        /// <summary>
        /// 獲取列表
        /// </summary>
        Task<List<MsgDM>> GetList(long userId, string title, long startTime, long endTime);

        /// <summary>
        /// 獲取實體
        /// </summary>
        Task<MsgDM> Get(string id);

        /// <summary>
        /// 更新實體
        /// </summary>
        Task<bool> Update(MsgDM data);

        /// <summary>
        /// 添加實體
        /// </summary>
        Task<string> Insert(MsgDM data);

        /// <summary>
        /// 刪除實體
        /// </summary>
        Task<bool> Delete(string id);
    }
復制代碼

 

 

對應的我們還需要打開MsgRepository.cs文件實現該接口:

  View Code

 

 

完成了上面關於數據庫的工作,下面我們就進入正題,開始實現gRpc服務了,首先我們在項目根目錄下新建MsgServiceImpl.cs文件,在其中實現我們協議中的服務:

  View Code

 

 

三、證書生成

 

a.安裝openssl

首先讀者需要從該網站下載openssl安裝程序:

Openssl下載

筆者的系統是Win10 64所以下載的是“Win64 OpenSSL v1.1.0b”。

 

b.制作證書

網上有很多的教程,但是對於新手來說直接給繞暈了,有的有ca、client和service有的沒有,這里筆者提供一個全面的cmd腳本(默認CA是自己):

復制代碼
 1 @echo off
 2 set OPENSSL_CONF=c:\OpenSSL-Win64\bin\openssl.cfg
 3 
 4 echo Generate CA key:
 5 openssl genrsa -passout pass:1111 -des3 -out ca.key 4096
 6 
 7 echo Generate CA certificate:
 8 openssl req -passin pass:1111 -new -x509 -days 365 -key ca.key -out ca.crt -subj  "/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root"
 9 
10 echo Generate server key:
11 openssl genrsa -passout pass:1111 -des3 -out server.key 4096
12 
13 echo Generate server signing request:
14 openssl req -passin pass:1111 -new -key server.key -out server.csr -subj  "/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root"
15 
16 echo Self-sign server certificate:
17 openssl x509 -req -passin pass:1111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
18 
19 echo Remove passphrase from server key:
20 openssl rsa -passin pass:1111 -in server.key -out server.key
21 
22 echo Generate client key
23 openssl genrsa -passout pass:1111 -des3 -out client.key 4096
24 
25 echo Generate client signing request:
26 openssl req -passin pass:1111 -new -key client.key -out client.csr -subj  "/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root"
27 
28 echo Self-sign client certificate:
29 openssl x509 -passin pass:1111 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
30 
31 echo Remove passphrase from client key:
32 openssl rsa -passin pass:1111 -in client.key -out client.key
復制代碼

 

以上的腳本也會生成我們下面Demo中使用的證書。

 

四、完善服務端

      用了上面的證書之后我們需要繼續把服務端啟動gRpc服務部分的代碼書寫完畢,這里筆者是采用命令行形式運行的,所以gRpc的啟動是獨立放在一個文件文件中,如下RpcConfiguration所示:

  View Code

其中我們使用了server.crtserver.key這兩個證書,所以在Host項目中需要將這個兩個證書文件copy到項目根目錄下,如果需要發布的時候包含則需要在project.json中配置如下節:

  "publishOptions": {
    "include": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json" ]
  }

最后我們需要在Program中啟動對應的gRpc即可。

 

五、客戶端編寫

      完成了服務端的編寫剩下的就是客戶端的編寫,當然客戶端的編寫相對容易很多,筆者這里直接把Sino.GrpcService.Protocol項目包含到客戶端解決方案中了(在正式開發中建議采用nuget包進行管理),為了簡單起見,所以只調用了其中一個服務接口:

復制代碼
public static class MsgServiceClient
    {
        private static Channel _channel;
        private static MsgService.MsgServiceClient _client;

        static MsgServiceClient()
        {
            var cacert = File.ReadAllText("server.crt");
            var ssl = new SslCredentials(cacert);
            var channOptions = new List<ChannelOption>
            {
                new ChannelOption(ChannelOptions.SslTargetNameOverride,"root")
            };
            _channel = new Channel("grpcservice.t0.daoapp.io:61130", ssl, channOptions);
            _client = new MsgService.MsgServiceClient(_channel);
        }

        public static GetMsgListReply GetList(int userId, string title, long startTime, long endTime)
        {
            return _client.GetList(new GetMsgListRequest
            {
                UserId = userId,
                Title = title,
                StartTime = startTime,
                EndTime = endTime
            });
        }
    }
復制代碼

需要注意下其中“ChannelOptions.SslTargetNameOverride”這部分是必須的,因為我們是自己生成的證書,所以域名是root,如果是生產環境可以不需要。

 

六、利用Docker運行

 

a.安裝Docker For Windows

      這里需要win10的系統,這樣可以直接在ps中直接利用docker指令了。

 

b.編寫Dockerfile

      因為1.1版本出來了,但是經過本人的驗證,如果你的應用不升級是無法使用該鏡像的,默認使用1.1,所以這里我們的Dockerfile需要指定下特定的版本,否則是無法構建的,我們首先在解決方案的根目錄下新建Dockerfile文件,然后在其中放入以下命令:

復制代碼
 1 FROM microsoft/dotnet:1.0-sdk-projectjson
 2 
 3 ADD ./ /usr/local/src
 4 WORKDIR /usr/local/src/Sino.GrpcService.Host/
 5 
 6 RUN cd /usr/local/src/
 7 RUN dotnet restore -v http://api.nuget.org/v3/index.json
 8 RUN dotnet build
 9 
10 EXPOSE 9007
11 
12 CMD ["dotnet","run"]
復制代碼

 

 

c.生成鏡像並運行

我們打開ps,然后cd到解決方案的文件夾下利用:

docker build -t gRpcService:1.0 .

 

開始構建,基於國內的情況建議大家將docker默認拉取鏡像的地址調整下。生成好之后,利用以下指令去啟動即可:

docker run -d –name -p 9007:9007 gRpcService gRpcService:1.0

 

當然客戶端連接的地址和端口也要根據-p指定的情況去調整。

 

七、其他

對應的源碼可以訪問以下地址:

 

https://github.com/Vip56/Sino.GrpcService

https://github.com/Vip56/Sino.GrpcClient

 

如果需要詢問相關問題的可以短消息給我。

 

Xamarin.Android -> Xamarin.IOS -> 混合 -> Xamarin.Forms


免責聲明!

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



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