.NET Core下使用gRpc公开服务(SSL/TLS)
<h1>一、前言</h1><p> </p>
<p><span style="font-size: 16px"> 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多的教程中基本都是泛泛而谈,难以实际在实际环境中使用,而该篇教程以gRpc为主,但是使用了其SSL/TLS,这样更加符合实际的生产使用,期间也会配套的讲解Docker、openssl等。</span></p>
<p> </p>
<h1>二、服务端</h1>
<p> </p>
<h3>a.准备工作</h3>
<p><span style="font-size: 16px">笔者的项目分为三个部分分别如下所示:</span></p>
<p><span style="font-size: 16px">Sino.GrpcService.Host(控制台):宿主程序</span></p>
<p><span style="font-size: 16px">Sino.GrpcService.Impl(类库):实现协议</span></p>
<p><span style="font-size: 16px">Sino.GrpcService.Protocol(类库):生成协议</span></p>
<p> </p>
<p>最终的项目如下图所示:</p>
<p><img src="https://images2015.cnblogs.com/blog/465329/201612/465329-20161212155828401-612430106.png" alt=""></p>
<p> </p>
<p>每个项目的project.json如下所示:</p>
<div class="cnblogs_code"><img id="code_img_closed_d2a5150f-74fd-4659-9446-eb0630f62512" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_d2a5150f-74fd-4659-9446-eb0630f62512" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_d2a5150f-74fd-4659-9446-eb0630f62512" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> "version": "1.0.0-*"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> "buildOptions"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> "emitEntryPoint": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> "copyToOutput": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json"<span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> "dependencies"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> "Microsoft.NETCore.App"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> "type": "platform"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">10</span> "version": "1.0.0"
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> },
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "Sino.GrpcService.Impl": "1.0.0-*"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">13</span> "Microsoft.Extensions.Configuration.Json": "1.0.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">14</span> "Microsoft.Extensions.Configuration.Binder": "1.0.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">15</span> "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0"
<span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">17</span> "frameworks"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">18</span> "netcoreapp1.0"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">19</span> "imports": [ "dnxcore50", "net452"<span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">22</span> "publishOptions"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">23</span> "include": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json"<span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">25</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p><span style="font-size: 16px">其中“buildOptions”和“publishOptions”中我们将后面我们需要的证书包含到输出和发布中,其中我们还利用了“Configuration”相关组件去读取配置信息。</span></p>
<p> </p>
<p><span style="font-size: 16px">Sino.GrpcService.Impl:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_d86f096c-47c5-482c-9fb6-15e4e716a92a" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_d86f096c-47c5-482c-9fb6-15e4e716a92a" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_d86f096c-47c5-482c-9fb6-15e4e716a92a" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> "version": "1.0.0-*"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> "dependencies"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> "Autofac": "4.1.1"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> "Google.Protobuf": "3.1.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> "Grpc.Core": "1.0.1-pre1"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> "NETStandard.Library": "1.6.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> "Sino.GrpcService.Protocol": "1.0.0-*"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> "MongoDB.Driver": "2.3.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">10</span> "Microsoft.Extensions.Configuration.Abstractions": "1.0.0"
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "frameworks"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">13</span> "netstandard1.6"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">14</span> "imports": "dnxcore50"
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">17</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p><span style="font-size: 16px">其中我们安装了“MongoDb.Driver”,为了能够贴近真实的情况,笔者这里采用MongoDb作为数据源来提供数据,当然读者为了能够快速上手可以硬编码一些数据。</span></p>
<p> </p>
<p><span style="font-size: 16px">Sino.GrpcService.Protocol:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_19828381-b1ca-4a71-b22c-439c946108a9" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_19828381-b1ca-4a71-b22c-439c946108a9" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_19828381-b1ca-4a71-b22c-439c946108a9" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> "version": "1.0.0-*"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> "dependencies"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> "Google.Protobuf": "3.1.0"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> "Grpc.Core": "1.0.1-pre1"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> "NETStandard.Library": "1.6.0"
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> "frameworks"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> "netstandard1.6"<span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> "imports": "dnxcore50"
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> },
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "net452"<span style="color: rgba(0, 0, 0, 1)">: {}
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">14</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><span style="font-size: 16px">至此项目的初始化结束。</span></p>
<p> </p>
<h3>b.编写协议</h3>
<p> <span style="font-size: 16px">首先我们打开Sino.GrpcService.Protocol项目,在其中新建一个msg.proto文件,打开msg.proto文件,我们将在其中编写基于proto3语言的协议,以便后面自动生成到各语言,如果读者需要更深入的学习可以打开该网站Proto3语言指南。</span></p>
<p><span style="font-size: 16px">这里我们定义我们当前使用的是proto3语言并且包名<span style="background-color: rgba(255, 255, 153, 1); color: rgba(255, 0, 0, 1)">(生成为C#则为命名空间)</span>为:</span></p>
<div class="cnblogs_code">
<pre>syntax = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">proto3</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
package Sino.GrpcService;</span></pre>
</div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">笔者为该服务定义了1个服务,且有4种方法:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">service MsgService{
rpc GetList(GetMsgListRequest) returns (GetMsgListReply){}
rpc GetOne(GetMsgOneRequest) returns (GetMsgOneReply){}
rpc Edit(EditMsgRequest) returns (EditMsgReply){}
rpc Remove(RemoveMsgRequest) returns (RemoveMsgReply){}
}</span></pre>
</div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">对应到其中每个方法的接收参数和返回参数的定义如下:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_f81d6382-c361-41f7-b166-a9e9b3f048d2" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_f81d6382-c361-41f7-b166-a9e9b3f048d2" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_f81d6382-c361-41f7-b166-a9e9b3f048d2" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">message GetMsgListRequest {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> int64 UserId = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Title = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> int64 StartTime = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> int64 EndTime = <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">message GetMsgListReply {
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">message MsgItem {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Title = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Content = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> int64 UserId = <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">14</span> int64 Time = <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">16</span> repeated MsgItem Items = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">17</span> int64 Count = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> IsSuccess = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ErrorMsg = <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">message GetMsgOneRequest {
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">25</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)">message GetMsgOneReply {
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Title = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Content = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">30</span> int64 UserId = <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">31</span> int64 Time = <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> IsSuccess = <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ErrorMsg = <span style="color: rgba(128, 0, 128, 1)">7</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">34</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">35</span>
<span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)">message EditMsgRequest {
</span><span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Title = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Content = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">40</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">41</span>
<span style="color: rgba(0, 128, 128, 1)">42</span> <span style="color: rgba(0, 0, 0, 1)">message EditMsgReply {
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> IsSuccess = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">44</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ErrorMsg = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">45</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">46</span>
<span style="color: rgba(0, 128, 128, 1)">47</span> <span style="color: rgba(0, 0, 0, 1)">message RemoveMsgRequest {
</span><span style="color: rgba(0, 128, 128, 1)">48</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">49</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">50</span>
<span style="color: rgba(0, 128, 128, 1)">51</span> <span style="color: rgba(0, 0, 0, 1)">message RemoveMsgReply {
</span><span style="color: rgba(0, 128, 128, 1)">52</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> IsSuccess = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ErrorMsg = <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">54</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p><span style="font-size: 16px">到这为止我们就完成了协议的编写。</span></p>
<p> </p>
<h3>c.将协议生成为C#代码</h3>
<p><span style="font-size: 16px"> 相对于网站的很多关于C#使用gRpc的教程都是基于.NET项目框架下的,所以可以安装gRpc.Tools,但是.NET Core安装后是找不到工具的,所以读者可以新建一个.NET项目安装该类库,然后将其中的工具复制到<strong><em>Sino.GrpcService.Protocol</em></strong>中,这里读者需要根据你当前的系统去选择,复制完成之后在该项目中新建一个名为<em><strong>“ProtocGenerate.cmd”</strong></em>的文件,在其中输入以下指令:</span></p>
<div class="cnblogs_code">
<pre>protoc -I . --csharp_out . --grpc_out . --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe msg.proto</pre>
</div>
<p> </p>
<p><span style="font-size: 16px">然后读者直接双击运行,就会看到项目下生成了“Msg.cs”和“MsgGrpc.cs”两个文件,这样就完成了所有协议部分的工作了,最终的项目结构如下所示:</span></p>
<p><img src="https://images2015.cnblogs.com/blog/465329/201612/465329-20161212160252495-1650868210.png" alt=""></p>
<p> </p>
<h3>d.编写实现代码</h3>
<p> <span style="font-size: 16px">有了协议层之后我们就可以开始编写实现了,因为笔者这里使用了MongoDb提供数据所以下文篇幅会较长。</span></p>
<p> </p>
<p><span style="font-size: 16px">首先打开<strong><em>Sino.GrpcService.Impl</em></strong>项目在其中新建Model文件,然后在该文件夹下新建<strong><em>MsgDM.cs</em></strong>文件,该文件主要是定义MongoDb存储的数据结构,具体内容如下所示:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_56f6b00e-fd04-4ca5-820d-beae8f18e10b" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_56f6b00e-fd04-4ca5-820d-beae8f18e10b" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_56f6b00e-fd04-4ca5-820d-beae8f18e10b" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 消息体
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">sealed</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MsgDM
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 编号
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">public</span> ObjectId Id { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 标题
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Title { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">15</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 内容
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Content { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">20</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 用户编号
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span> UserId { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">25</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 时间
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span> Time { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">30</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">紧接着我们新建<em><strong>Repositories</strong></em>文件夹,在其中新建四个文件分别为<strong><em>“IDataContext.cs”、“DataContext.cs”、“IMsgRepository.cs”和“MsgRepository.cs”</em></strong>。打开IDataContext.cs文件在其中编写如下内容:</span></p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 数据库上下文
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> IDataContext
{
IMongoDatabase Database { </span><span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}</span></pre>
</div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">打开DataContext.cs文件进行数据库初始化相关工作:</span></p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> DataContext : IDataContext
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> IMongoDatabase Database { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> DataContext(IConfigurationRoot config)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> client = <span style="color: rgba(0, 0, 255, 1)">new</span> MongoClient(config.GetConnectionString(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongodb</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">));
Database </span>= client.GetDatabase(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">aSQ0cWkEshl8NiVn</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">打开IMsgRepository.cs,我们需要在其中定义仓储提供的操作:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 消息仓储
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> IMsgRepository
{
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取列表
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
Task<List<MsgDM>> GetList(<span style="color: rgba(0, 0, 255, 1)">long</span> userId, <span style="color: rgba(0, 0, 255, 1)">string</span> title, <span style="color: rgba(0, 0, 255, 1)">long</span> startTime, <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> endTime);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取实体
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
Task<MsgDM> Get(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> id);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 更新实体
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>><span style="color: rgba(0, 0, 0, 1)"> Update(MsgDM data);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 添加实体
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
Task<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> Insert(MsgDM data);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 删除实体
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>> Delete(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> id);
}</span></pre>
</div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">对应的我们还需要打开MsgRepository.cs文件实现该接口:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_703f6c15-cf08-410f-92cb-bb0bd81c0bcf" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_703f6c15-cf08-410f-92cb-bb0bd81c0bcf" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_703f6c15-cf08-410f-92cb-bb0bd81c0bcf" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MsgRepository : IMsgRepository
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> IDataContext _dataContext;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">private</span> IMongoCollection<MsgDM><span style="color: rgba(0, 0, 0, 1)"> _collection;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MsgRepository(IDataContext dataContext)
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> _dataContext =<span style="color: rgba(0, 0, 0, 1)"> dataContext;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> _collection = _dataContext.Database.GetCollection<MsgDM>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">msg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>> Delete(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> id)
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">var</span> filter = Builders<MsgDM>.Filter.Eq(x => x.Id, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectId(id));
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _collection.DeleteOneAsync(filter);
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">return</span> result.DeletedCount == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">18</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 255, 1)">public</span> Task<MsgDM> Get(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> id)
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 255, 1)">var</span> objectId = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectId(id);
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = (<span style="color: rgba(0, 0, 255, 1)">from</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> _collection.AsQueryable()
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 255, 1)">where</span> item.Id ==<span style="color: rgba(0, 0, 0, 1)"> objectId
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 255, 1)">select</span><span style="color: rgba(0, 0, 0, 1)"> item).FirstOrDefault();
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Task.FromResult(result);
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">27</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 255, 1)">public</span> Task<List<MsgDM>> GetList(<span style="color: rgba(0, 0, 255, 1)">long</span> userId, <span style="color: rgba(0, 0, 255, 1)">string</span> title, <span style="color: rgba(0, 0, 255, 1)">long</span> startTime, <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> endTime)
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">30</span> IQueryable<MsgDM> filter =<span style="color: rgba(0, 0, 0, 1)"> _collection.AsQueryable();
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (userId != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">32</span> filter = filter.Where(x => x.UserId ==<span style="color: rgba(0, 0, 0, 1)"> userId);
</span><span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrEmpty(title))
</span><span style="color: rgba(0, 128, 128, 1)">34</span> filter = filter.Where(x =><span style="color: rgba(0, 0, 0, 1)"> x.Title.Contains(title));
</span><span style="color: rgba(0, 128, 128, 1)">35</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (startTime != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">36</span> filter = filter.Where(x => x.Time ><span style="color: rgba(0, 0, 0, 1)"> startTime);
</span><span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (endTime != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">38</span> filter = filter.Where(x => x.Time <<span style="color: rgba(0, 0, 0, 1)"> startTime);
</span><span style="color: rgba(0, 128, 128, 1)">39</span>
<span style="color: rgba(0, 128, 128, 1)">40</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Task.FromResult(filter.ToList());
</span><span style="color: rgba(0, 128, 128, 1)">41</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">42</span>
<span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> Insert(MsgDM data)
</span><span style="color: rgba(0, 128, 128, 1)">44</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">45</span> <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _collection.InsertOneAsync(data);
</span><span style="color: rgba(0, 128, 128, 1)">46</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> data.Id.ToString();
</span><span style="color: rgba(0, 128, 128, 1)">47</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">48</span>
<span style="color: rgba(0, 128, 128, 1)">49</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>><span style="color: rgba(0, 0, 0, 1)"> Update(MsgDM data)
</span><span style="color: rgba(0, 128, 128, 1)">50</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">51</span> <span style="color: rgba(0, 0, 255, 1)">var</span> filter = Builders<MsgDM>.Filter.Eq(x =><span style="color: rgba(0, 0, 0, 1)"> x.Id, data.Id);
</span><span style="color: rgba(0, 128, 128, 1)">52</span> <span style="color: rgba(0, 0, 255, 1)">var</span> update = Builders<MsgDM>.Update.Set(x => x.Title, data.Title).Set(x =><span style="color: rgba(0, 0, 0, 1)"> x.Content, data.Content);
</span><span style="color: rgba(0, 128, 128, 1)">53</span>
<span style="color: rgba(0, 128, 128, 1)">54</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = <span style="color: rgba(0, 0, 255, 1)">await</span> _collection.UpdateOneAsync(Builders<MsgDM>.Filter.Eq(x =><span style="color: rgba(0, 0, 0, 1)"> x.Id, data.Id), update);
</span><span style="color: rgba(0, 128, 128, 1)">55</span>
<span style="color: rgba(0, 128, 128, 1)">56</span> <span style="color: rgba(0, 0, 255, 1)">return</span> result.ModifiedCount == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">57</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">58</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p> </p>
<p><span style="font-size: 16px">完成了上面关于数据库的工作,下面我们就进入正题,开始实现gRpc服务了,首先我们在项目根目录下新建MsgServiceImpl.cs文件,在其中实现我们协议中的服务:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_10fb7ce1-1e8b-4a0d-92ff-79e0e4825fce" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_10fb7ce1-1e8b-4a0d-92ff-79e0e4825fce" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_10fb7ce1-1e8b-4a0d-92ff-79e0e4825fce" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MsgServiceImpl : MsgService.MsgServiceBase
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> IMsgRepository _msgRepository;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MsgServiceImpl(IMsgRepository msgRepository)
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> _msgRepository =<span style="color: rgba(0, 0, 0, 1)"> msgRepository;
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<GetMsgListReply><span style="color: rgba(0, 0, 0, 1)"> GetList(GetMsgListRequest request, ServerCallContext context)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GetMsgListReply();
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">var</span> list = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _msgRepository.GetList(request.UserId, request.Title, request.StartTime, request.EndTime);
</span><span style="color: rgba(0, 128, 128, 1)">14</span> result.IsSuccess = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">15</span> result.Items.AddRange(list.Select(x => <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GetMsgListReply.Types.MsgItem
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">17</span> UserId =<span style="color: rgba(0, 0, 0, 1)"> x.UserId,
</span><span style="color: rgba(0, 128, 128, 1)">18</span> Title =<span style="color: rgba(0, 0, 0, 1)"> x.Title,
</span><span style="color: rgba(0, 128, 128, 1)">19</span> Time =<span style="color: rgba(0, 0, 0, 1)"> x.Time,
</span><span style="color: rgba(0, 128, 128, 1)">20</span> Content =<span style="color: rgba(0, 0, 0, 1)"> x.Content
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)"> }).ToList());
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">24</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<EditMsgReply><span style="color: rgba(0, 0, 0, 1)"> Edit(EditMsgRequest request, ServerCallContext context)
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> EditMsgReply();
</span><span style="color: rgba(0, 128, 128, 1)">28</span> result.IsSuccess = <span style="color: rgba(0, 0, 255, 1)">await</span> _msgRepository.Update(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MsgDM
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">30</span> Id = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MongoDB.Bson.ObjectId(request.Id),
</span><span style="color: rgba(0, 128, 128, 1)">31</span> Title =<span style="color: rgba(0, 0, 0, 1)"> request.Title,
</span><span style="color: rgba(0, 128, 128, 1)">32</span> Content =<span style="color: rgba(0, 0, 0, 1)"> request.Content
</span><span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 0, 1)"> });
</span><span style="color: rgba(0, 128, 128, 1)">34</span>
<span style="color: rgba(0, 128, 128, 1)">35</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
</span><span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">37</span>
<span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<GetMsgOneReply><span style="color: rgba(0, 0, 0, 1)"> GetOne(GetMsgOneRequest request, ServerCallContext context)
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">40</span> <span style="color: rgba(0, 0, 255, 1)">var</span> msg = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _msgRepository.Get(request.Id);
</span><span style="color: rgba(0, 128, 128, 1)">41</span>
<span style="color: rgba(0, 128, 128, 1)">42</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GetMsgOneReply
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">44</span> IsSuccess = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">45</span> Id =<span style="color: rgba(0, 0, 0, 1)"> msg.Id.ToString(),
</span><span style="color: rgba(0, 128, 128, 1)">46</span> UserId =<span style="color: rgba(0, 0, 0, 1)"> msg.UserId,
</span><span style="color: rgba(0, 128, 128, 1)">47</span> Title =<span style="color: rgba(0, 0, 0, 1)"> msg.Title,
</span><span style="color: rgba(0, 128, 128, 1)">48</span> Content =<span style="color: rgba(0, 0, 0, 1)"> msg.Content,
</span><span style="color: rgba(0, 128, 128, 1)">49</span> Time =<span style="color: rgba(0, 0, 0, 1)"> msg.Time
</span><span style="color: rgba(0, 128, 128, 1)">50</span> <span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 128, 1)">51</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">52</span>
<span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<RemoveMsgReply><span style="color: rgba(0, 0, 0, 1)"> Remove(RemoveMsgRequest request, ServerCallContext context)
</span><span style="color: rgba(0, 128, 128, 1)">54</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">55</span> <span style="color: rgba(0, 0, 255, 1)">var</span> result = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RemoveMsgReply();
</span><span style="color: rgba(0, 128, 128, 1)">56</span> result.IsSuccess = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _msgRepository.Delete(request.Id);
</span><span style="color: rgba(0, 128, 128, 1)">57</span>
<span style="color: rgba(0, 128, 128, 1)">58</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
</span><span style="color: rgba(0, 128, 128, 1)">59</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">60</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> </p>
<p> </p>
<h1>三、证书生成</h1>
<p> </p>
<h3>a.安装openssl</h3>
<p><span style="font-size: 16px">首先读者需要从该网站下载openssl安装程序:</span></p>
<p><span style="font-size: 16px">Openssl下载</span></p>
<p><span style="font-size: 16px">笔者的系统是Win10 64所以下载的是“Win64 OpenSSL v1.1.0b”。</span></p>
<p> </p>
<h3>b.制作证书</h3>
<p><span style="font-size: 16px">网上有很多的教程,但是对于新手来说直接给绕晕了,有的有ca、client和service有的没有,这里笔者提供一个全面的cmd脚本<span style="background-color: rgba(255, 255, 153, 1); color: rgba(255, 0, 0, 1)">(默认CA是自己)</span>:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">@echo off
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> set OPENSSL_CONF=c:\OpenSSL-<span style="color: rgba(0, 0, 0, 1)">Win64\bin\openssl.cfg
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate CA key:
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> openssl genrsa -passout pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -des3 -out ca.key <span style="color: rgba(128, 0, 128, 1)">4096</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate CA certificate:
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> openssl req -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -new -x509 -days <span style="color: rgba(128, 0, 128, 1)">365</span> -key ca.key -out ca.crt -subj<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate server key:
</span><span style="color: rgba(0, 128, 128, 1)">11</span> openssl genrsa -passout pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -des3 -out server.key <span style="color: rgba(128, 0, 128, 1)">4096</span>
<span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate server signing request:
</span><span style="color: rgba(0, 128, 128, 1)">14</span> openssl req -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -new -key server.key -out server.csr -subj<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">15</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> Self-<span style="color: rgba(0, 0, 0, 1)">sign server certificate:
</span><span style="color: rgba(0, 128, 128, 1)">17</span> openssl x509 -req -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -days <span style="color: rgba(128, 0, 128, 1)">365</span> -<span style="color: rgba(0, 0, 255, 1)">in</span> server.csr -CA ca.crt -CAkey ca.key -set_serial <span style="color: rgba(128, 0, 128, 1)">01</span> -<span style="color: rgba(0, 0, 0, 1)">out server.crt
</span><span style="color: rgba(0, 128, 128, 1)">18</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Remove passphrase from server key:
</span><span style="color: rgba(0, 128, 128, 1)">20</span> openssl rsa -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -<span style="color: rgba(0, 0, 255, 1)">in</span> server.key -<span style="color: rgba(0, 0, 0, 1)">out server.key
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate client key
</span><span style="color: rgba(0, 128, 128, 1)">23</span> openssl genrsa -passout pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -des3 -out client.key <span style="color: rgba(128, 0, 128, 1)">4096</span>
<span style="color: rgba(0, 128, 128, 1)">24</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Generate client signing request:
</span><span style="color: rgba(0, 128, 128, 1)">26</span> openssl req -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -new -key client.key -out client.csr -subj<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/C=CN/ST=JS/L=ZJ/O=sino/OU=test/CN=root</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">27</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> Self-<span style="color: rgba(0, 0, 0, 1)">sign client certificate:
</span><span style="color: rgba(0, 128, 128, 1)">29</span> openssl x509 -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -req -days <span style="color: rgba(128, 0, 128, 1)">365</span> -<span style="color: rgba(0, 0, 255, 1)">in</span> client.csr -CA ca.crt -CAkey ca.key -set_serial <span style="color: rgba(128, 0, 128, 1)">01</span> -<span style="color: rgba(0, 0, 0, 1)">out client.crt
</span><span style="color: rgba(0, 128, 128, 1)">30</span>
<span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 255, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"> Remove passphrase from client key:
</span><span style="color: rgba(0, 128, 128, 1)">32</span> openssl rsa -passin pass:<span style="color: rgba(128, 0, 128, 1)">1111</span> -<span style="color: rgba(0, 0, 255, 1)">in</span> client.key -out client.key</pre>
</div>
<p> </p>
<p><span style="font-size: 16px">以上的脚本也会生成我们下面Demo中使用的证书。</span></p>
<p> </p>
<h1>四、完善服务端</h1>
<p> <span style="font-size: 16px"> 用了上面的证书之后我们需要继续把服务端启动gRpc服务部分的代码书写完毕,这里笔者是采用命令行形式运行的,所以gRpc的启动是独立放在一个文件文件中,如下<strong><em>RpcConfiguration</em></strong>所示:</span></p>
<div class="cnblogs_code"><img id="code_img_closed_85ac7bc3-83ea-4de9-bac9-49fad232d6c3" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_85ac7bc3-83ea-4de9-bac9-49fad232d6c3" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_85ac7bc3-83ea-4de9-bac9-49fad232d6c3" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RpcConfiguration
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> Server _server;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> IContainer _container;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Start(IConfigurationRoot config)
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 255, 1)">var</span> builder = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ContainerBuilder();
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> builder.RegisterInstance(config).As<IConfigurationRoot><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">11</span> builder.RegisterInstance(<span style="color: rgba(0, 0, 255, 1)">new</span> DataContext(config)).As<IDataContext><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">12</span> builder.RegisterAssemblyTypes(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(IDataContext).GetTypeInfo().Assembly).Where(t => t.Name.EndsWith(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Repository</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)).AsImplementedInterfaces();
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> _container =<span style="color: rgba(0, 0, 0, 1)"> builder.Build();
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 255, 1)">var</span> servercert = File.ReadAllText(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">server.crt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">var</span> serverkey = File.ReadAllText(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">server.key</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 255, 1)">var</span> keypair = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> KeyCertificatePair(servercert, serverkey);
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 255, 1)">var</span> sslCredentials = <span style="color: rgba(0, 0, 255, 1)">new</span> SslServerCredentials(<span style="color: rgba(0, 0, 255, 1)">new</span> List<KeyCertificatePair><span style="color: rgba(0, 0, 0, 1)">() { keypair });
</span><span style="color: rgba(0, 128, 128, 1)">19</span> _server = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Server
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">21</span> Services = { MsgService.BindService(<span style="color: rgba(0, 0, 255, 1)">new</span> MsgServiceImpl(_container.Resolve<IMsgRepository><span style="color: rgba(0, 0, 0, 1)">())) },
</span><span style="color: rgba(0, 128, 128, 1)">22</span> Ports = { <span style="color: rgba(0, 0, 255, 1)">new</span> ServerPort(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">0.0.0.0</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">9007</span><span style="color: rgba(0, 0, 0, 1)">, sslCredentials) }
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 0, 1)"> _server.Start();
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)"> _server.ShutdownTask.Wait();
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">27</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Stop()
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">30</span> _server?<span style="color: rgba(0, 0, 0, 1)">.ShutdownAsync().Wait();
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">32</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><span style="font-size: 16px">其中我们使用了<em><strong>server.crt</strong></em>和<em><strong>server.key</strong></em>这两个证书,所以在Host项目中需要将这个两个证书文件copy到项目根目录下,如果需要发布的时候包含则需要在project.json中配置如下节:</span></p>
<div class="cnblogs_code">
<pre>"publishOptions"<span style="color: rgba(0, 0, 0, 1)">: {
</span>"include": [ "server.crt", "server.key", "appSettings.json", "appSettings.*.json"<span style="color: rgba(0, 0, 0, 1)"> ]
}</span></pre>
</div>
<p><span style="font-size: 16px">最后我们需要在Program中启动对应的gRpc即可。</span></p>
<p> </p>
<h1>五、客户端编写</h1>
<p> <span style="font-size: 16px">完成了服务端的编写剩下的就是客户端的编写,当然客户端的编写相对容易很多,笔者这里直接把<strong><em>Sino.GrpcService.Protocol</em></strong>项目包含到客户端解决方案中了(在正式开发中建议采用nuget包进行管理),为了简单起见,所以只调用了其中一个服务接口:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MsgServiceClient
{
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> Channel _channel;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> MsgService.MsgServiceClient _client;
</span><span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> MsgServiceClient()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cacert = File.ReadAllText(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">server.crt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> ssl = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SslCredentials(cacert);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> channOptions = <span style="color: rgba(0, 0, 255, 1)">new</span> List<ChannelOption><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">new</span> ChannelOption(ChannelOptions.SslTargetNameOverride,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">root</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
};
_channel </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Channel(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">grpcservice.t0.daoapp.io:61130</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, ssl, channOptions);
_client </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MsgService.MsgServiceClient(_channel);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> GetMsgListReply GetList(<span style="color: rgba(0, 0, 255, 1)">int</span> userId, <span style="color: rgba(0, 0, 255, 1)">string</span> title, <span style="color: rgba(0, 0, 255, 1)">long</span> startTime, <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> endTime)
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> _client.GetList(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GetMsgListRequest
{
UserId </span>=<span style="color: rgba(0, 0, 0, 1)"> userId,
Title </span>=<span style="color: rgba(0, 0, 0, 1)"> title,
StartTime </span>=<span style="color: rgba(0, 0, 0, 1)"> startTime,
EndTime </span>=<span style="color: rgba(0, 0, 0, 1)"> endTime
});
}
}</span></pre>
</div>
<p><span style="font-size: 16px">需要注意下其中“<em><strong>ChannelOptions.SslTargetNameOverride</strong></em>”这部分是必须的,因为我们是自己生成的证书,所以域名是root,如果是生产环境可以不需要。</span></p>
<p> </p>
<h1>六、利用Docker运行</h1>
<p> </p>
<h3>a.安装Docker For Windows</h3>
<p> <span style="font-size: 16px">这里需要win10的系统,这样可以直接在ps中直接利用docker指令了。</span></p>
<p> </p>
<h3>b.编写Dockerfile</h3>
<p> <span style="font-size: 16px"> 因为<span lang="EN-US">1.1</span>版本出来了,但是经过本人的验证,如果你的应用不升级是无法使用该镜像的,默认使用<span lang="EN-US">1.1</span>,所以这里我们的<span lang="EN-US">Dockerfile</span>需要指定下特定的版本,否则是无法构建的,我们首先在解决方案的根目录下新建<span lang="EN-US">Dockerfile</span>文件,然后在其中放入以下命令:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> FROM microsoft/dotnet:<span style="color: rgba(128, 0, 128, 1)">1.0</span>-sdk-<span style="color: rgba(0, 0, 0, 1)">projectjson
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> ADD ./ /usr/local/<span style="color: rgba(0, 0, 0, 1)">src
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> WORKDIR /usr/local/src/Sino.GrpcService.Host/
<span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> RUN cd /usr/local/src/
<span style="color: rgba(0, 128, 128, 1)"> 7</span> RUN dotnet restore -v http:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">api.nuget.org/v3/index.json</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">RUN dotnet build
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> EXPOSE <span style="color: rgba(128, 0, 128, 1)">9007</span>
<span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> CMD [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">dotnet</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">run</span><span style="color: rgba(128, 0, 0, 1)">"</span>]</pre>
</div>
<p> </p>
<p> </p>
<h3>c.生成镜像并运行</h3>
<p><span style="font-size: 16px">我们打开<span lang="EN-US">ps</span>,然后<span lang="EN-US">cd</span>到解决方案的文件夹下利用:</span></p>
<div class="cnblogs_code">
<pre>docker build -t gRpcService:<span style="color: rgba(128, 0, 128, 1)">1.0</span> .</pre>
</div>
<p> </p>
<p><span style="font-size: 16px">开始构建,基于国内的情况建议大家将<span lang="EN-US">docker</span>默认拉取镜像的地址调整下。生成好之后,利用以下指令去启动即可:</span></p>
<div class="cnblogs_code">
<pre>docker run -d –name -p <span style="color: rgba(128, 0, 128, 1)">9007</span>:<span style="color: rgba(128, 0, 128, 1)">9007</span> gRpcService gRpcService:<span style="color: rgba(128, 0, 128, 1)">1.0</span></pre>
</div>
<p> </p>
<p><span style="font-size: 16px">当然客户端连接的地址和端口也要根据<span lang="EN-US">-p</span>指定的情况去调整。</span></p>
<p> </p>
<h1>七、其他</h1>
<p><span style="font-size: 16px">对应的源码可以访问以下地址:</span></p>
<p> </p>
<p><span style="font-size: 16px" lang="EN-US">https://github.com/Vip56/Sino.GrpcService</span></p>
<p><span style="font-size: 16px"><span lang="EN-US">https://github.com/Vip56/Sino.GrpcClient</span></span></p>
<p> </p>
<p><span style="font-size: 16px">如果需要询问相关问题的可以短消息给我。</span></p>
</div>
<div id="MySignature" role="contentinfo">
Xamarin.Android -> Xamarin.IOS -> 混合 -> Xamarin.Forms<br><br>
来源:https://www.cnblogs.com/yaozhenfa/p/gRpc_with_ssl.html
頁:
[1]