日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Core下使用gRpc公开服务(SSL/TLS)

發布時間:2023/12/4 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .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如下所示:

{

? "version": "1.0.0-*",

? "buildOptions": {

? ? "emitEntryPoint": true,

? ? "copyToOutput": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json" ]

? },

? "dependencies": {

? ? "Microsoft.NETCore.App": {

? ? ? "type": "platform",

? ? ? "version": "1.0.0"

? ? },

? ? "Sino.GrpcService.Impl": "1.0.0-*",

? ? "Microsoft.Extensions.Configuration.Json": "1.0.0",

? ? "Microsoft.Extensions.Configuration.Binder": "1.0.0",

? ? "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0"

? },

? "frameworks": {

? ? "netcoreapp1.0": {

? ? ? "imports": [ "dnxcore50", "net452" ]

? ? }

? },

? "publishOptions": {

? ? "include": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json" ]

? }

}

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

Sino.GrpcService.Impl:

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

Sino.GrpcService.Protocol:


至此項目的初始化結束。?

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){}

}

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

message GetMsgListRequest {

? int64 UserId = 1;

? string Title = 2;

? int64 StartTime = 3;

? int64 EndTime = 4;

}


message GetMsgListReply {

? message MsgItem {

? ? string Id = 1;

? ? string Title = 2;

? ? string Content = 3;

? ? int64 UserId = 4;

? ? int64 Time = 5;

? }

? repeated MsgItem Items = 1;

? int64 Count = 2;

? bool IsSuccess = 3;

? string ErrorMsg = 4;

}


message GetMsgOneRequest {

? string Id = 1;

}


message GetMsgOneReply {

? string Id = 1;

? string Title = 2;

? string Content = 3;

? int64 UserId = 4;

? int64 Time = 5;

? bool IsSuccess = 6;

? string ErrorMsg = 7;

}


message EditMsgRequest {

? string Id = 1;

? string Title = 2;

? string Content = 3;

}


message EditMsgReply {

? bool IsSuccess = 1;

? string ErrorMsg = 2;

}


message RemoveMsgRequest {

? string Id = 1;

}


message RemoveMsgReply {

? bool IsSuccess = 1;

? string ErrorMsg = 2;

}

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

?

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存儲的數據結構,具體內容如下所示:

/// <summary>

? ? /// 消息體

? ? /// </summary>

? ? public sealed class MsgDM

? ? {

? ? ? ? /// <summary>

? ? ? ? /// 編號

? ? ? ? /// </summary>

? ? ? ? public ObjectId Id { get; set; }


? ? ? ? /// <summary>

? ? ? ? /// 標題

? ? ? ? /// </summary>

? ? ? ? public string Title { get; set; }


? ? ? ? /// <summary>

? ? ? ? /// 內容

? ? ? ? /// </summary>

? ? ? ? public string Content { get; set; }


? ? ? ? /// <summary>

? ? ? ? /// 用戶編號

? ? ? ? /// </summary>

? ? ? ? public long UserId { get; set; }


? ? ? ? /// <summary>

? ? ? ? /// 時間

? ? ? ? /// </summary>

? ? ? ? public long Time { get; set; }

? ? }

緊接著我們新建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文件實現該接口:

public class MsgRepository : IMsgRepository

? ? {

? ? ? ? private IDataContext _dataContext;

? ? ? ? private IMongoCollection<MsgDM> _collection;


? ? ? ? public MsgRepository(IDataContext dataContext)

? ? ? ? {

? ? ? ? ? ? _dataContext = dataContext;

? ? ? ? ? ? _collection = _dataContext.Database.GetCollection<MsgDM>("msg");

? ? ? ? }


? ? ? ? public async Task<bool> Delete(string id)

? ? ? ? {

? ? ? ? ? ? var filter = Builders<MsgDM>.Filter.Eq(x => x.Id, new ObjectId(id));

? ? ? ? ? ? var result = await _collection.DeleteOneAsync(filter);

? ? ? ? ? ? return result.DeletedCount == 1;

? ? ? ? }


? ? ? ? public Task<MsgDM> Get(string id)

? ? ? ? {

? ? ? ? ? ? var objectId = new ObjectId(id);

? ? ? ? ? ? var result = (from item in _collection.AsQueryable()

? ? ? ? ? ? ? ? ? ? ? ? ? where item.Id == objectId

? ? ? ? ? ? ? ? ? ? ? ? ? select item).FirstOrDefault();

? ? ? ? ? ? return Task.FromResult(result);

? ? ? ? }


? ? ? ? public Task<List<MsgDM>> GetList(long userId, string title, long startTime, long endTime)

? ? ? ? {

? ? ? ? ? ? IQueryable<MsgDM> filter = _collection.AsQueryable();

? ? ? ? ? ? if (userId != 0)

? ? ? ? ? ? ? ? filter = filter.Where(x => x.UserId == userId);

? ? ? ? ? ? if (!string.IsNullOrEmpty(title))

? ? ? ? ? ? ? ? filter = filter.Where(x => x.Title.Contains(title));

? ? ? ? ? ? if (startTime != 0)

? ? ? ? ? ? ? ? filter = filter.Where(x => x.Time > startTime);

? ? ? ? ? ? if (endTime != 0)

? ? ? ? ? ? ? ? filter = filter.Where(x => x.Time < startTime);


? ? ? ? ? ? return Task.FromResult(filter.ToList());

? ? ? ? }


? ? ? ? public async Task<string> Insert(MsgDM data)

? ? ? ? {

? ? ? ? ? ? await _collection.InsertOneAsync(data);

? ? ? ? ? ? return data.Id.ToString();

? ? ? ? }


? ? ? ? public async Task<bool> Update(MsgDM data)

? ? ? ? {

? ? ? ? ? ? var filter = Builders<MsgDM>.Filter.Eq(x => x.Id, data.Id);

? ? ? ? ? ? var update = Builders<MsgDM>.Update.Set(x => x.Title, data.Title).Set(x => x.Content, data.Content);


? ? ? ? ? ? var result = await _collection.UpdateOneAsync(Builders<MsgDM>.Filter.Eq(x => x.Id, data.Id), update);


? ? ? ? ? ? return result.ModifiedCount == 1;

? ? ? ? }

? ? }

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

public class MsgServiceImpl : MsgService.MsgServiceBase

? ? {

? ? ? ? private IMsgRepository _msgRepository;


? ? ? ? public MsgServiceImpl(IMsgRepository msgRepository)

? ? ? ? {

? ? ? ? ? ? _msgRepository = msgRepository;

? ? ? ? }


? ? ? ? public override async Task<GetMsgListReply> GetList(GetMsgListRequest request, ServerCallContext context)

? ? ? ? {

? ? ? ? ? ? var result = new GetMsgListReply();

? ? ? ? ? ? var list = await _msgRepository.GetList(request.UserId, request.Title, request.StartTime, request.EndTime);

? ? ? ? ? ? result.IsSuccess = true;

? ? ? ? ? ? result.Items.AddRange(list.Select(x => new GetMsgListReply.Types.MsgItem

? ? ? ? ? ? {

? ? ? ? ? ? ? ? UserId = x.UserId,

? ? ? ? ? ? ? ? Title = x.Title,

? ? ? ? ? ? ? ? Time = x.Time,

? ? ? ? ? ? ? ? Content = x.Content

? ? ? ? ? ? }).ToList());

? ? ? ? ? ? return result;

? ? ? ? }


? ? ? ? public override async Task<EditMsgReply> Edit(EditMsgRequest request, ServerCallContext context)

? ? ? ? {

? ? ? ? ? ? var result = new EditMsgReply();

? ? ? ? ? ? result.IsSuccess = await _msgRepository.Update(new MsgDM

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Id = new MongoDB.Bson.ObjectId(request.Id),

? ? ? ? ? ? ? ? Title = request.Title,

? ? ? ? ? ? ? ? Content = request.Content

? ? ? ? ? ? });


? ? ? ? ? ? return result;

? ? ? ? }


? ? ? ? public override async Task<GetMsgOneReply> GetOne(GetMsgOneRequest request, ServerCallContext context)

? ? ? ? {

? ? ? ? ? ? var msg = await _msgRepository.Get(request.Id);


? ? ? ? ? ? return new GetMsgOneReply

? ? ? ? ? ? {

? ? ? ? ? ? ? ? IsSuccess = true,

? ? ? ? ? ? ? ? Id = msg.Id.ToString(),

? ? ? ? ? ? ? ? UserId = msg.UserId,

? ? ? ? ? ? ? ? Title = msg.Title,

? ? ? ? ? ? ? ? Content = msg.Content,

? ? ? ? ? ? ? ? Time = msg.Time

? ? ? ? ? ? };

? ? ? ? }


? ? ? ? public override async Task<RemoveMsgReply> Remove(RemoveMsgRequest request, ServerCallContext context)

? ? ? ? {

? ? ? ? ? ? var result = new RemoveMsgReply();

? ? ? ? ? ? result.IsSuccess = await _msgRepository.Delete(request.Id);


? ? ? ? ? ? return result;

? ? ? ? }

? ? }

三、證書生成

?

a.安裝openssl

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

Openssl下載

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

?

b.制作證書

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

@echo off

set OPENSSL_CONF=c:\OpenSSL-Win64\bin\openssl.cfg


echo Generate CA key:

openssl genrsa -passout pass:1111 -des3 -out ca.key 4096


echo Generate CA certificate:

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"


echo Generate server key:

openssl genrsa -passout pass:1111 -des3 -out server.key 4096


echo Generate server signing request:

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"


echo Self-sign server certificate:

openssl x509 -req -passin pass:1111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt


echo Remove passphrase from server key:

openssl rsa -passin pass:1111 -in server.key -out server.key


echo Generate client key

openssl genrsa -passout pass:1111 -des3 -out client.key 4096


echo Generate client signing request:

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"


echo Self-sign client certificate:

openssl x509 -passin pass:1111 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt


echo Remove passphrase from client key:

openssl rsa -passin pass:1111 -in client.key -out client.key

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

?

四、完善服務端

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


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

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

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

?

五、客戶端編寫

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


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

?

六、利用Docker運行

?

a.安裝Docker For Windows

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

?

b.編寫Dockerfile

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

FROM microsoft/dotnet:1.0-sdk-projectjson


ADD ./ /usr/local/src

WORKDIR /usr/local/src/Sino.GrpcService.Host/


RUN cd /usr/local/src/

RUN dotnet restore -v http://api.nuget.org/v3/index.json

RUN dotnet build


EXPOSE 9007


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

相關文章:?

  • gRPC .NET Core跨平臺學習

  • 谷歌發布的首款基于HTTP/2和protobuf的RPC框架:GRPC

  • C#中使用gRPC

  • Google高性能RPC框架gRPC 1.0.0發布

原文地址:http://www.cnblogs.com/yaozhenfa/p/gRpc_with_ssl.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的.NET Core下使用gRpc公开服务(SSL/TLS)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。