前一陣子關於.NET的各大公衆號都發表了關於gRpc的消息,而隨之而來的就是一波關於.NET Core下如何使用的教程,可是在這衆多的教程中基本都是泛泛而談,難以實際在實際環境中使用,而該篇教程以gRpc爲主,可是使用了其SSL/TLS,這樣更加符合實際的生產使用,期間也會配套的講解Docker、openssl等。html
筆者的項目分爲三個部分分別以下所示:web
Sino.GrpcService.Host(控制檯):宿主程序mongodb
Sino.GrpcService.Impl(類庫):實現協議docker
Sino.GrpcService.Protocol(類庫):生成協議數據庫
最終的項目以下圖所示:json
每一個項目的project.json以下所示:api
其中「buildOptions」和「publishOptions」中咱們將後面咱們須要的證書包含到輸出和發佈中,其中咱們還利用了「Configuration」相關組件去讀取配置信息。數據結構
Sino.GrpcService.Impl:app
其中咱們安裝了「MongoDb.Driver」,爲了可以貼近真實的狀況,筆者這裏採用MongoDb做爲數據源來提供數據,固然讀者爲了可以快速上手能夠硬編碼一些數據。框架
Sino.GrpcService.Protocol:
至此項目的初始化結束。
首先咱們打開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){} }
對應到其中每一個方法的接收參數和返回參數的定義以下:
到這爲止咱們就完成了協議的編寫。
相對於網站的不少關於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」兩個文件,這樣就完成了全部協議部分的工做了,最終的項目結構以下所示:
有了協議層以後咱們就能夠開始編寫實現了,由於筆者這裏使用了MongoDb提供數據因此下文篇幅會較長。
首先打開Sino.GrpcService.Impl項目在其中新建Model文件,而後在該文件夾下新建MsgDM.cs文件,該文件主要是定義MongoDb存儲的數據結構,具體內容以下所示:
緊接着咱們新建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文件實現該接口:
完成了上面關於數據庫的工做,下面咱們就進入正題,開始實現gRpc服務了,首先咱們在項目根目錄下新建MsgServiceImpl.cs文件,在其中實現咱們協議中的服務:
首先讀者須要從該網站下載openssl安裝程序:
筆者的系統是Win10 64因此下載的是「Win64 OpenSSL v1.1.0b」。
網上有不少的教程,可是對於新手來講直接給繞暈了,有的有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所示:
其中咱們使用了server.crt和server.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,若是是生產環境能夠不須要。
這裏須要win10的系統,這樣能夠直接在ps中直接利用docker指令了。
由於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"]
咱們打開ps,而後cd到解決方案的文件夾下利用:
docker build -t gRpcService:1.0 .
開始構建,基於國內的狀況建議你們將docker默認拉取鏡像的地址調整下。生成好以後,利用如下指令去啓動便可:
docker run -d –name -p 9007:9007 gRpcService gRpcService:1.0
固然客戶端鏈接的地址和端口也要根據-p指定的狀況去調整。