├── .gitattributes ├── .gitignore ├── Consul ├── conf │ └── 只为生成此目录.txt ├── consul.exe ├── data │ ├── checkpoint-signature │ ├── node-id │ ├── proxy │ │ └── snapshot.json │ ├── raft │ │ ├── peers.info │ │ ├── raft.db │ │ └── raft.db.lock │ ├── serf │ │ ├── local.snapshot │ │ └── remote.snapshot │ └── 只为生成此目录.txt ├── dist │ └── 只为生成此目录.txt └── startup.bat ├── DMS.GrpcConsul.Client ├── Consul │ ├── AppFind.cs │ ├── Entity │ │ └── HealthCheck.cs │ └── IAppFind.cs ├── DMS.GrpcConsul.Client.csproj ├── Framework │ ├── DependencyInitialize.cs │ └── Entity │ │ ├── ConsulService.cs │ │ └── GrpcServiceSettings.cs ├── LoadBalance │ ├── ILoadBalance.cs │ └── WeightRoundBalance.cs ├── Program.cs ├── RpcClient │ ├── IMsgClient.cs │ └── MsgClient.cs ├── Utils │ └── HttpHelper.cs └── appsettings.json ├── DMS.GrpcConsul.Hosting ├── Consul │ ├── AppRregister.cs │ └── Entity │ │ ├── ConsulService.cs │ │ └── HealthService.cs ├── Controllers │ └── ValuesController.cs ├── DMS.GrpcConsul.Hosting.csproj ├── Program.cs ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ├── DMS.GrpcConsul.Impl ├── DMS.GrpcConsul.Impl.csproj ├── Entity │ └── GrpcService.cs ├── IRpcConfig.cs ├── RpcConfig.cs └── RpcService │ └── MsgServiceImpl.cs ├── DMS.GrpcConsul.Protocol ├── DMS.GrpcConsul.Protocol.csproj ├── Msg.cs ├── MsgGrpc.cs └── tools │ ├── ProtocGenerate.bat │ ├── grpc_csharp_plugin.exe │ ├── msg.proto │ └── protoc.exe ├── DMS.GrpcConsul.sln └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | #[Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.pch 68 | *.pdb 69 | *.pgc 70 | *.pgd 71 | *.rsp 72 | *.sbr 73 | *.tlb 74 | *.tli 75 | *.tlh 76 | *.tmp 77 | *.tmp_proj 78 | *.log 79 | *.vspscc 80 | *.vssscc 81 | .builds 82 | *.pidb 83 | *.svclog 84 | *.scc 85 | 86 | # Chutzpah Test files 87 | _Chutzpah* 88 | 89 | # Visual C++ cache files 90 | ipch/ 91 | *.aps 92 | *.ncb 93 | *.opendb 94 | *.opensdf 95 | *.sdf 96 | *.cachefile 97 | *.VC.db 98 | *.VC.VC.opendb 99 | 100 | # Visual Studio profiler 101 | *.psess 102 | *.vsp 103 | *.vspx 104 | *.sap 105 | 106 | # Visual Studio Trace Files 107 | *.e2e 108 | 109 | # TFS 2012 Local Workspace 110 | $tf/ 111 | 112 | # Guidance Automation Toolkit 113 | *.gpState 114 | 115 | # ReSharper is a .NET coding add-in 116 | _ReSharper*/ 117 | *.[Rr]e[Ss]harper 118 | *.DotSettings.user 119 | 120 | # JustCode is a .NET coding add-in 121 | .JustCode 122 | 123 | # TeamCity is a build add-in 124 | _TeamCity* 125 | 126 | # DotCover is a Code Coverage Tool 127 | *.dotCover 128 | 129 | # AxoCover is a Code Coverage Tool 130 | .axoCover/* 131 | !.axoCover/settings.json 132 | 133 | # Visual Studio code coverage results 134 | *.coverage 135 | *.coveragexml 136 | 137 | # NCrunch 138 | _NCrunch_* 139 | .*crunch*.local.xml 140 | nCrunchTemp_* 141 | 142 | # MightyMoose 143 | *.mm.* 144 | AutoTest.Net/ 145 | 146 | # Web workbench (sass) 147 | .sass-cache/ 148 | 149 | # Installshield output folder 150 | [Ee]xpress/ 151 | 152 | # DocProject is a documentation generator add-in 153 | DocProject/buildhelp/ 154 | DocProject/Help/*.HxT 155 | DocProject/Help/*.HxC 156 | DocProject/Help/*.hhc 157 | DocProject/Help/*.hhk 158 | DocProject/Help/*.hhp 159 | DocProject/Help/Html2 160 | DocProject/Help/html 161 | 162 | # Click-Once directory 163 | publish/ 164 | 165 | # Publish Web Output 166 | *.[Pp]ublish.xml 167 | *.azurePubxml 168 | # Note: Comment the next line if you want to checkin your web deploy settings, 169 | # but database connection strings (with potential passwords) will be unencrypted 170 | *.pubxml 171 | *.publishproj 172 | 173 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 174 | # checkin your Azure Web App publish settings, but sensitive information contained 175 | # in these scripts will be unencrypted 176 | PublishScripts/ 177 | 178 | # NuGet Packages 179 | *.nupkg 180 | # The packages folder can be ignored because of Package Restore 181 | **/[Pp]ackages/* 182 | # except build/, which is used as an MSBuild target. 183 | !**/[Pp]ackages/build/ 184 | # Uncomment if necessary however generally it will be regenerated when needed 185 | #!**/[Pp]ackages/repositories.config 186 | # NuGet v3's project.json files produces more ignorable files 187 | *.nuget.props 188 | *.nuget.targets 189 | 190 | # Microsoft Azure Build Output 191 | csx/ 192 | *.build.csdef 193 | 194 | # Microsoft Azure Emulator 195 | ecf/ 196 | rcf/ 197 | 198 | # Windows Store app package directories and files 199 | AppPackages/ 200 | BundleArtifacts/ 201 | Package.StoreAssociation.xml 202 | _pkginfo.txt 203 | *.appx 204 | 205 | # Visual Studio cache files 206 | # files ending in .cache can be ignored 207 | *.[Cc]ache 208 | # but keep track of directories ending in .cache 209 | !*.[Cc]ache/ 210 | 211 | # Others 212 | ClientBin/ 213 | ~$* 214 | *~ 215 | *.dbmdl 216 | *.dbproj.schemaview 217 | *.jfm 218 | *.pfx 219 | *.publishsettings 220 | orleans.codegen.cs 221 | 222 | # Including strong name files can present a security risk 223 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 224 | #*.snk 225 | 226 | # Since there are multiple workflows, uncomment next line to ignore bower_components 227 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 228 | #bower_components/ 229 | 230 | # RIA/Silverlight projects 231 | Generated_Code/ 232 | 233 | # Backup & report files from converting an old project file 234 | # to a newer Visual Studio version. Backup files are not needed, 235 | # because we have git ;-) 236 | _UpgradeReport_Files/ 237 | Backup*/ 238 | UpgradeLog*.XML 239 | UpgradeLog*.htm 240 | ServiceFabricBackup/ 241 | 242 | # SQL Server files 243 | *.mdf 244 | *.ldf 245 | *.ndf 246 | 247 | # Business Intelligence projects 248 | *.rdl.data 249 | *.bim.layout 250 | *.bim_*.settings 251 | 252 | # Microsoft Fakes 253 | FakesAssemblies/ 254 | 255 | # GhostDoc plugin setting file 256 | *.GhostDoc.xml 257 | 258 | # Node.js Tools for Visual Studio 259 | .ntvs_analysis.dat 260 | node_modules/ 261 | 262 | # Visual Studio 6 build log 263 | *.plg 264 | 265 | # Visual Studio 6 workspace options file 266 | *.opt 267 | 268 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 269 | *.vbw 270 | 271 | # Visual Studio LightSwitch build output 272 | **/*.HTMLClient/GeneratedArtifacts 273 | **/*.DesktopClient/GeneratedArtifacts 274 | **/*.DesktopClient/ModelManifest.xml 275 | **/*.Server/GeneratedArtifacts 276 | **/*.Server/ModelManifest.xml 277 | _Pvt_Extensions 278 | 279 | # Paket dependency manager 280 | .paket/paket.exe 281 | paket-files/ 282 | 283 | # FAKE - F# Make 284 | .fake/ 285 | 286 | # JetBrains Rider 287 | .idea/ 288 | *.sln.iml 289 | 290 | # CodeRush 291 | .cr/ 292 | 293 | # Python Tools for Visual Studio (PTVS) 294 | __pycache__/ 295 | *.pyc 296 | 297 | # Cake - Uncomment if you are using it 298 | # tools/** 299 | # !tools/packages.config 300 | 301 | # Tabs Studio 302 | *.tss 303 | 304 | # Telerik's JustMock configuration file 305 | *.jmconfig 306 | 307 | # BizTalk build output 308 | *.btp.cs 309 | *.btm.cs 310 | *.odx.cs 311 | *.xsd.cs 312 | 313 | # OpenCover UI analysis results 314 | OpenCover/ 315 | 316 | # Azure Stream Analytics local run output 317 | ASALocalRun/ 318 | 319 | # MSBuild Binary and Structured Log 320 | *.binlog -------------------------------------------------------------------------------- /Consul/conf/只为生成此目录.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/conf/只为生成此目录.txt -------------------------------------------------------------------------------- /Consul/consul.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/consul.exe -------------------------------------------------------------------------------- /Consul/data/checkpoint-signature: -------------------------------------------------------------------------------- 1 | 2bf4fb92-8dd6-b7ff-66c8-0c6cb253f072 2 | 3 | 4 | This signature is a randomly generated UUID used to de-duplicate 5 | alerts and version information. This signature is random, it is 6 | not based on any personally identifiable information. To create 7 | a new signature, you can simply delete this file at any time. 8 | See the documentation for the software using Checkpoint for more 9 | information on how to disable it. 10 | 11 | -------------------------------------------------------------------------------- /Consul/data/node-id: -------------------------------------------------------------------------------- 1 | e191fdd6-9d78-6a38-5c30-779b76be389f -------------------------------------------------------------------------------- /Consul/data/proxy/snapshot.json: -------------------------------------------------------------------------------- 1 | {"Version":1,"Proxies":{}} -------------------------------------------------------------------------------- /Consul/data/raft/peers.info: -------------------------------------------------------------------------------- 1 | 2 | As of Consul 0.7.0, the peers.json file is only used for recovery 3 | after an outage. The format of this file depends on what the server has 4 | configured for its Raft protocol version. Please see the agent configuration 5 | page at https://www.consul.io/docs/agent/options.html#_raft_protocol for more 6 | details about this parameter. 7 | 8 | For Raft protocol version 2 and earlier, this should be formatted as a JSON 9 | array containing the address and port of each Consul server in the cluster, like 10 | this: 11 | 12 | [ 13 | "10.1.0.1:8300", 14 | "10.1.0.2:8300", 15 | "10.1.0.3:8300" 16 | ] 17 | 18 | For Raft protocol version 3 and later, this should be formatted as a JSON 19 | array containing the node ID, address:port, and suffrage information of each 20 | Consul server in the cluster, like this: 21 | 22 | [ 23 | { 24 | "id": "adf4238a-882b-9ddc-4a9d-5b6758e4159e", 25 | "address": "10.1.0.1:8300", 26 | "non_voter": false 27 | }, 28 | { 29 | "id": "8b6dda82-3103-11e7-93ae-92361f002671", 30 | "address": "10.1.0.2:8300", 31 | "non_voter": false 32 | }, 33 | { 34 | "id": "97e17742-3103-11e7-93ae-92361f002671", 35 | "address": "10.1.0.3:8300", 36 | "non_voter": false 37 | } 38 | ] 39 | 40 | The "id" field is the node ID of the server. This can be found in the logs when 41 | the server starts up, or in the "node-id" file inside the server's data 42 | directory. 43 | 44 | The "address" field is the address and port of the server. 45 | 46 | The "non_voter" field controls whether the server is a non-voter, which is used 47 | in some advanced Autopilot configurations, please see 48 | https://www.consul.io/docs/guides/autopilot.html for more information. If 49 | "non_voter" is omitted it will default to false, which is typical for most 50 | clusters. 51 | 52 | Under normal operation, the peers.json file will not be present. 53 | 54 | When Consul starts for the first time, it will create this peers.info file and 55 | delete any existing peers.json file so that recovery doesn't occur on the first 56 | startup. 57 | 58 | Once this peers.info file is present, any peers.json file will be ingested at 59 | startup, and will set the Raft peer configuration manually to recover from an 60 | outage. It's crucial that all servers in the cluster are shut down before 61 | creating the peers.json file, and that all servers receive the same 62 | configuration. Once the peers.json file is successfully ingested and applied, it 63 | will be deleted. 64 | 65 | Please see https://www.consul.io/docs/guides/outage.html for more information. 66 | -------------------------------------------------------------------------------- /Consul/data/raft/raft.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/data/raft/raft.db -------------------------------------------------------------------------------- /Consul/data/raft/raft.db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/data/raft/raft.db.lock -------------------------------------------------------------------------------- /Consul/data/serf/local.snapshot: -------------------------------------------------------------------------------- 1 | alive: grpc-consul1 127.0.0.1:8301 2 | event-clock: 1 3 | alive: grpc-consul1 127.0.0.1:8301 4 | event-clock: 2 5 | alive: grpc-consul1 127.0.0.1:8301 6 | event-clock: 3 7 | alive: grpc-consul1 127.0.0.1:8301 8 | event-clock: 4 9 | alive: grpc-consul1 127.0.0.1:8301 10 | event-clock: 5 11 | -------------------------------------------------------------------------------- /Consul/data/serf/remote.snapshot: -------------------------------------------------------------------------------- 1 | alive: grpc-consul1.grpc-consul 127.0.0.1:8302 2 | alive: grpc-consul1.grpc-consul 127.0.0.1:8302 3 | alive: grpc-consul1.grpc-consul 127.0.0.1:8302 4 | alive: grpc-consul1.grpc-consul 127.0.0.1:8302 5 | alive: grpc-consul1.grpc-consul 127.0.0.1:8302 6 | -------------------------------------------------------------------------------- /Consul/data/只为生成此目录.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/data/只为生成此目录.txt -------------------------------------------------------------------------------- /Consul/dist/只为生成此目录.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/Consul/dist/只为生成此目录.txt -------------------------------------------------------------------------------- /Consul/startup.bat: -------------------------------------------------------------------------------- 1 | consul agent -server -datacenter=grpc-consul -bootstrap -data-dir ./data -ui -node=grpc-consul1 -bind 127.0.0.1 -client=0.0.0.0 -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Consul/AppFind.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Client.Consul.Entity; 2 | using DMS.GrpcConsul.Client.Framework.Entity; 3 | using DMS.GrpcConsul.Client.Utils; 4 | using Microsoft.Extensions.Options; 5 | using Newtonsoft.Json; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace DMS.GrpcConsul.Client.Consul 11 | { 12 | /* 13 | * 服务发现 14 | * (服务和健康信息)http://localhost:8500/v1/health/service/GrpcService 15 | * (健康信息)http://localhost:8500/v1/health/checks/GrpcService 16 | */ 17 | public class AppFind: IAppFind 18 | { 19 | static IOptions GrpcSettings; 20 | static IOptions ConsulSettings; 21 | 22 | public AppFind(IOptions grpcSettings, IOptions consulSettings) 23 | { 24 | GrpcSettings = grpcSettings; 25 | ConsulSettings = consulSettings; 26 | } 27 | 28 | public IEnumerable FindConsul(string ServiceName) 29 | { 30 | Dictionary headers = new Dictionary(); 31 | 32 | var consul = ConsulSettings.Value; 33 | string findUrl = $"http://{consul.IP}:{consul.Port}/v1/health/checks/{ServiceName}"; 34 | 35 | string findResult = HttpHelper.HttpGet(findUrl, headers, 5); 36 | if (findResult.Equals("")) 37 | { 38 | var grpcServices = GrpcSettings.Value.GrpcServices; 39 | return grpcServices.Where(g=>g.ServiceName.Equals(ServiceName,StringComparison.CurrentCultureIgnoreCase)).Select(s => s.ServiceID); 40 | } 41 | 42 | var findCheck = JsonConvert.DeserializeObject>(findResult); 43 | 44 | return findCheck.Where(g => g.Status.Equals("passing", StringComparison.CurrentCultureIgnoreCase)).Select(g => g.ServiceID); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Consul/Entity/HealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DMS.GrpcConsul.Client.Consul.Entity 6 | { 7 | public class HealthCheck 8 | { 9 | public string Node { get; set; } 10 | public string CheckID { get; set; } 11 | public string Name { get; set; } 12 | public string Status { get; set; } 13 | public string Notes { get; set; } 14 | public string Output { get; set; } 15 | public string ServiceID { get; set; } 16 | public string ServiceName { get; set; } 17 | public string[] ServiceTags { get; set; } 18 | public dynamic Definition { get; set; } 19 | public int CreateIndex { get; set; } 20 | public int ModifyIndex { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Consul/IAppFind.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DMS.GrpcConsul.Client.Consul 4 | { 5 | public interface IAppFind 6 | { 7 | IEnumerable FindConsul(string ServiceName); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/DMS.GrpcConsul.Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Framework/DependencyInitialize.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Client.Consul; 2 | using DMS.GrpcConsul.Client.Framework.Entity; 3 | using DMS.GrpcConsul.Client.LoadBalance; 4 | using DMS.GrpcConsul.Client.RpcClient; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using System; 8 | using System.IO; 9 | 10 | namespace DMS.GrpcConsul.Client.Framework 11 | { 12 | /* 13 | * IServiceCollection 依赖注入生命周期 14 | * AddTransient 每次都是全新的 15 | * AddScoped 在一个范围之内只有同一个实例(同一个线程,同一个浏览器请求只有一个实例) 16 | * AddSingleton 单例 17 | */ 18 | public static class DependencyInitialize 19 | { 20 | /// 21 | /// 注册对象 22 | /// 23 | /// The services. 24 | /* 25 | * IAppFind AppFind; 26 | * 构造函数注入使用 IAppFind appFind 27 | * AppFind = appFind; 28 | */ 29 | public static void AddImplement(this IServiceCollection services) 30 | { 31 | //添加 json 文件路径 32 | var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); 33 | //创建配置根对象 34 | var configurationRoot = builder.Build(); 35 | 36 | //注册全局配置 37 | services.AddConfigImplement(configurationRoot); 38 | 39 | //注册服务发现 40 | services.AddScoped(); 41 | 42 | //注册负载均衡 43 | if (configurationRoot["LoadBalancer"].Equals("WeightRound", StringComparison.CurrentCultureIgnoreCase)) 44 | { 45 | services.AddSingleton(); 46 | } 47 | 48 | //注册Rpc客户端 49 | services.AddTransient(); 50 | } 51 | 52 | /// 53 | /// 注册全局配置 54 | /// 55 | /// The services. 56 | /// The configurationRoot. 57 | /* 58 | * IOptions GrpcSettings; 59 | * 构造函数注入使用 IOptions grpcSettings 60 | * GrpcSettings = grpcSettings; 61 | */ 62 | public static void AddConfigImplement(this IServiceCollection services, IConfigurationRoot configurationRoot) 63 | { 64 | //注册配置对象 65 | services.AddOptions(); 66 | services.Configure(configurationRoot.GetSection(nameof(GrpcServiceSettings))); 67 | services.Configure(configurationRoot.GetSection(nameof(ConsulService))); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Framework/Entity/ConsulService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DMS.GrpcConsul.Client.Framework.Entity 6 | { 7 | public class ConsulService 8 | { 9 | public string IP { get; set; } 10 | public int Port { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Framework/Entity/GrpcServiceSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DMS.GrpcConsul.Client.Framework.Entity 6 | { 7 | public class GrpcServiceSettings 8 | { 9 | public List GrpcServices { get; set; } 10 | } 11 | 12 | public class GrpcService 13 | { 14 | public string ServiceName { get; set; } 15 | public string ServiceID { get; set; } 16 | public string IP { get; set; } 17 | public int Port { get; set; } 18 | public int Weight { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/LoadBalance/ILoadBalance.cs: -------------------------------------------------------------------------------- 1 | namespace DMS.GrpcConsul.Client.LoadBalance 2 | { 3 | /* 4 | * 负载均衡接口 5 | */ 6 | public interface ILoadBalance 7 | { 8 | string GetGrpcService(string ServiceName); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/LoadBalance/WeightRoundBalance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using DMS.GrpcConsul.Client.Consul; 5 | using DMS.GrpcConsul.Client.Framework.Entity; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace DMS.GrpcConsul.Client.LoadBalance 9 | { 10 | /* 11 | * 权重轮询 12 | */ 13 | public class WeightRoundBalance : ILoadBalance 14 | { 15 | int Balance; 16 | IOptions GrpcSettings; 17 | IAppFind AppFind; 18 | 19 | public WeightRoundBalance(IOptions grpcSettings, IAppFind appFind) 20 | { 21 | Balance = 0; 22 | GrpcSettings = grpcSettings; 23 | AppFind = appFind; 24 | } 25 | 26 | public string GetGrpcService(string ServiceName) 27 | { 28 | var grpcServices = GrpcSettings.Value.GrpcServices; 29 | 30 | var healthServiceID = AppFind.FindConsul(ServiceName); 31 | 32 | if (grpcServices == null || grpcServices.Count() == 0 || healthServiceID == null || healthServiceID.Count() == 0) 33 | { 34 | return ""; 35 | } 36 | 37 | //健康的服务 38 | var healthServices = new List(); 39 | 40 | foreach (var service in grpcServices) 41 | { 42 | foreach (var health in healthServiceID) 43 | { 44 | if (service.ServiceID.Equals(health, StringComparison.CurrentCultureIgnoreCase)) 45 | { 46 | healthServices.Add(service); 47 | break; 48 | } 49 | } 50 | } 51 | 52 | if (healthServices == null || healthServices.Count() == 0) 53 | { 54 | return ""; 55 | } 56 | 57 | //加权轮询 58 | var services = new List(); 59 | 60 | foreach (var service in healthServices) 61 | { 62 | services.AddRange(Enumerable.Repeat(service.IP + ":" + service.Port, service.Weight)); 63 | } 64 | 65 | var servicesArray = services.ToArray(); 66 | 67 | Balance = Balance % servicesArray.Length; 68 | var grpcUrl = servicesArray[Balance]; 69 | Balance = Balance + 1; 70 | 71 | return grpcUrl; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Client.Framework; 2 | using DMS.GrpcConsul.Client.RpcClient; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System; 5 | 6 | namespace DMS.GrpcConsul.Client 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | IServiceCollection service = new ServiceCollection(); 13 | 14 | //注册对象 15 | service.AddImplement(); 16 | 17 | //注入使用对象 18 | var provider = service.BuildServiceProvider(); 19 | 20 | string exeArg = string.Empty; 21 | Console.WriteLine("Grpc调用!"); 22 | Console.WriteLine("-c\t调用Grpc服务;"); 23 | Console.WriteLine("-q\t退出服务;"); 24 | 25 | while (true) 26 | { 27 | exeArg = Console.ReadKey().KeyChar.ToString(); 28 | Console.WriteLine(); 29 | 30 | if (exeArg.ToLower().Equals("c", StringComparison.CurrentCultureIgnoreCase)) 31 | { 32 | //调用服务 33 | var rpcClient = provider.GetService(); 34 | rpcClient.GetSum(10, 2); 35 | } 36 | else if (exeArg.ToLower().Equals("q", StringComparison.CurrentCultureIgnoreCase)) 37 | { 38 | break; 39 | } 40 | else 41 | { 42 | Console.WriteLine("参数异常!"); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/RpcClient/IMsgClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DMS.GrpcConsul.Client.RpcClient 6 | { 7 | public interface IMsgClient 8 | { 9 | void GetSum(int num1, int num2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/RpcClient/MsgClient.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Client.LoadBalance; 2 | using DMS.GrpcConsul.Protocol; 3 | using Grpc.Core; 4 | using System; 5 | 6 | namespace DMS.GrpcConsul.Client.RpcClient 7 | { 8 | public class MsgClient: IMsgClient 9 | { 10 | ILoadBalance LoadBalance; 11 | Channel GrpcChannel; 12 | MsgService.MsgServiceClient GrpcClient; 13 | 14 | public MsgClient(ILoadBalance loadBalance) 15 | { 16 | LoadBalance = loadBalance; 17 | 18 | var grpcUrl = LoadBalance.GetGrpcService("GrpcService"); 19 | 20 | if (!grpcUrl.Equals("")) 21 | { 22 | Console.WriteLine($"Grpc Service:{grpcUrl}"); 23 | 24 | GrpcChannel = new Channel(grpcUrl, ChannelCredentials.Insecure); 25 | GrpcClient = new MsgService.MsgServiceClient(GrpcChannel); 26 | } 27 | } 28 | 29 | public void GetSum(int num1, int num2) 30 | { 31 | if (GrpcClient != null) 32 | { 33 | GetMsgSumReply msgSum = GrpcClient.GetSum(new GetMsgNumRequest 34 | { 35 | Num1 = num1, 36 | Num2 = num2 37 | }); 38 | 39 | Console.WriteLine("Grpc Client Call GetSum():" + msgSum.Sum); 40 | } 41 | else 42 | { 43 | Console.WriteLine("所有负载都挂掉了!"); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/Utils/HttpHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DMS.GrpcConsul.Client.Utils 8 | { 9 | public class HttpHelper 10 | { 11 | /// 12 | /// 同步GET请求 13 | /// 14 | /// 15 | /// 16 | /// 请求响应超时时间,单位/s(默认100秒) 17 | /// 18 | public static string HttpGet(string url, Dictionary headers = null, int timeout = 0) 19 | { 20 | using (HttpClient client = new HttpClient()) 21 | { 22 | if (headers != null) 23 | { 24 | foreach (KeyValuePair header in headers) 25 | { 26 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 27 | } 28 | } 29 | if (timeout > 0) 30 | { 31 | client.Timeout = new TimeSpan(0, 0, timeout); 32 | } 33 | Byte[] resultBytes = client.GetByteArrayAsync(url).Result; 34 | return Encoding.UTF8.GetString(resultBytes); 35 | } 36 | } 37 | 38 | /// 39 | /// 异步GET请求 40 | /// 41 | /// 42 | /// 43 | /// 请求响应超时时间,单位/s(默认100秒) 44 | /// 45 | public static async Task HttpGetAsync(string url, Dictionary headers = null, int timeout = 0) 46 | { 47 | using (HttpClient client = new HttpClient()) 48 | { 49 | if (headers != null) 50 | { 51 | foreach (KeyValuePair header in headers) 52 | { 53 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 54 | } 55 | } 56 | if (timeout > 0) 57 | { 58 | client.Timeout = new TimeSpan(0, 0, timeout); 59 | } 60 | Byte[] resultBytes = await client.GetByteArrayAsync(url); 61 | return Encoding.Default.GetString(resultBytes); 62 | } 63 | } 64 | 65 | 66 | /// 67 | /// 同步POST请求 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | /// 请求响应超时时间,单位/s(默认100秒) 74 | /// 默认UTF8 75 | /// 76 | public static string HttpPost(string url, string postData, Dictionary headers = null, string contentType = null, int timeout = 0, Encoding encoding = null) 77 | { 78 | using (HttpClient client = new HttpClient()) 79 | { 80 | if (headers != null) 81 | { 82 | foreach (KeyValuePair header in headers) 83 | { 84 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 85 | } 86 | } 87 | if (timeout > 0) 88 | { 89 | client.Timeout = new TimeSpan(0, 0, timeout); 90 | } 91 | using (HttpContent content = new StringContent(postData ?? "", encoding ?? Encoding.UTF8)) 92 | { 93 | if (contentType != null) 94 | { 95 | content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); 96 | } 97 | using (HttpResponseMessage responseMessage = client.PostAsync(url, content).Result) 98 | { 99 | Byte[] resultBytes = responseMessage.Content.ReadAsByteArrayAsync().Result; 100 | return Encoding.UTF8.GetString(resultBytes); 101 | } 102 | } 103 | } 104 | } 105 | 106 | /// 107 | /// 异步POST请求 108 | /// 109 | /// 110 | /// 111 | /// 112 | /// 113 | /// 请求响应超时时间,单位/s(默认100秒) 114 | /// 默认UTF8 115 | /// 116 | public static async Task HttpPostAsync(string url, string postData, Dictionary headers = null, string contentType = null, int timeout = 0, Encoding encoding = null) 117 | { 118 | using (HttpClient client = new HttpClient()) 119 | { 120 | if (headers != null) 121 | { 122 | foreach (KeyValuePair header in headers) 123 | { 124 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 125 | } 126 | } 127 | if (timeout > 0) 128 | { 129 | client.Timeout = new TimeSpan(0, 0, timeout); 130 | } 131 | using (HttpContent content = new StringContent(postData ?? "", encoding ?? Encoding.UTF8)) 132 | { 133 | if (contentType != null) 134 | { 135 | content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); 136 | } 137 | using (HttpResponseMessage responseMessage = await client.PostAsync(url, content)) 138 | { 139 | Byte[] resultBytes = await responseMessage.Content.ReadAsByteArrayAsync(); 140 | return Encoding.UTF8.GetString(resultBytes); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Client/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "GrpcServiceSettings": { 3 | "GrpcServices": [ 4 | { 5 | "ServiceName": "GrpcService", 6 | "ServiceID": "GrpcService_5021", 7 | "IP": "localhost", 8 | "Port": "5031", 9 | "Weight": "2" 10 | }, 11 | { 12 | "ServiceName": "GrpcService", 13 | "ServiceID": "GrpcService_5022", 14 | "IP": "localhost", 15 | "Port": "5032", 16 | "Weight": "1" 17 | } 18 | ] 19 | }, 20 | "LoadBalancer": "WeightRound", 21 | "ConsulService": { 22 | "IP": "localhost", 23 | "Port": "8500" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Consul/AppRregister.cs: -------------------------------------------------------------------------------- 1 | using Consul; 2 | using DMS.GrpcConsul.Hosting.Consul.Entity; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.Options; 6 | using System; 7 | 8 | namespace DMS.GrpcConsul.Hosting.Consul 9 | { 10 | public static class AppRregister 11 | { 12 | // 服务注册 13 | public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, IOptions healthService, IOptions consulService) 14 | { 15 | var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{consulService.Value.IP}:{consulService.Value.Port}"));//请求注册的 Consul 地址 16 | var httpCheck = new AgentServiceCheck() 17 | { 18 | DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 19 | Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔 20 | HTTP = $"http://{healthService.Value.IP}:{healthService.Value.Port}/health",//健康检查地址 21 | Timeout = TimeSpan.FromSeconds(5) 22 | }; 23 | 24 | // Register service with consul 25 | var registration = new AgentServiceRegistration() 26 | { 27 | Checks = new[] { httpCheck }, 28 | ID = healthService.Value.Name + "_" + healthService.Value.Port, 29 | Name = healthService.Value.Name, 30 | Address = healthService.Value.IP, 31 | Port = healthService.Value.Port, 32 | Tags = new[] { $"urlprefix-/{healthService.Value.Name}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别 33 | }; 34 | 35 | consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起) 36 | lifetime.ApplicationStopping.Register(() => 37 | { 38 | consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册 39 | }); 40 | 41 | return app; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Consul/Entity/ConsulService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace DMS.GrpcConsul.Hosting.Consul.Entity 7 | { 8 | public class ConsulService 9 | { 10 | public string IP { get; set; } 11 | public int Port { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Consul/Entity/HealthService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace DMS.GrpcConsul.Hosting.Consul.Entity 7 | { 8 | public class HealthService 9 | { 10 | public string Name { get; set; } 11 | public string IP { get; set; } 12 | public int Port { get; set; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace DMS.GrpcConsul.Hosting.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | [ApiController] 11 | public class ValuesController : ControllerBase 12 | { 13 | // GET api/values 14 | [HttpGet] 15 | public ActionResult> Get() 16 | { 17 | return new string[] { "value1", "value2" }; 18 | } 19 | 20 | // GET api/values/5 21 | [HttpGet("{id}")] 22 | public ActionResult Get(int id) 23 | { 24 | return "value"; 25 | } 26 | 27 | // POST api/values 28 | [HttpPost] 29 | public void Post([FromBody] string value) 30 | { 31 | } 32 | 33 | // PUT api/values/5 34 | [HttpPut("{id}")] 35 | public void Put(int id, [FromBody] string value) 36 | { 37 | } 38 | 39 | // DELETE api/values/5 40 | [HttpDelete("{id}")] 41 | public void Delete(int id) 42 | { 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/DMS.GrpcConsul.Hosting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace DMS.GrpcConsul.Hosting 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseUrls("http://localhost:5021") 23 | .UseStartup(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using DMS.GrpcConsul.Hosting.Consul; 6 | using DMS.GrpcConsul.Hosting.Consul.Entity; 7 | using DMS.GrpcConsul.Impl; 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.AspNetCore.Http; 11 | using Microsoft.AspNetCore.HttpsPolicy; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.Extensions.Configuration; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using Microsoft.Extensions.Logging; 16 | using Microsoft.Extensions.Options; 17 | 18 | namespace DMS.GrpcConsul.Hosting 19 | { 20 | public class Startup 21 | { 22 | public Startup(IConfiguration configuration) 23 | { 24 | Configuration = configuration; 25 | } 26 | 27 | public IConfiguration Configuration { get; } 28 | 29 | // This method gets called by the runtime. Use this method to add services to the container. 30 | public void ConfigureServices(IServiceCollection services) 31 | { 32 | //注册全局配置 33 | services.AddOptions(); 34 | services.Configure(Configuration.GetSection(nameof(Impl.Entity.GrpcService))); 35 | services.Configure(Configuration.GetSection(nameof(HealthService))); 36 | services.Configure(Configuration.GetSection(nameof(ConsulService))); 37 | 38 | //注册Rpc服务 39 | services.AddSingleton(); 40 | 41 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 42 | } 43 | 44 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 45 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime, IOptions healthService, IOptions consulService, IRpcConfig rpc) 46 | { 47 | if (env.IsDevelopment()) 48 | { 49 | app.UseDeveloperExceptionPage(); 50 | } 51 | else 52 | { 53 | app.UseHsts(); 54 | } 55 | 56 | // 添加健康检查路由地址 57 | app.Map("/health", HealthMap); 58 | 59 | // 服务注册 60 | app.RegisterConsul(lifetime, healthService, consulService); 61 | 62 | // 启动Rpc服务 63 | rpc.Start(); 64 | 65 | app.UseHttpsRedirection(); 66 | app.UseMvc(); 67 | } 68 | 69 | private static void HealthMap(IApplicationBuilder app) 70 | { 71 | app.Run(async context => 72 | { 73 | await context.Response.WriteAsync("OK"); 74 | }); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Hosting/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*", 8 | "GrpcService": { 9 | "IP": "localhost", 10 | "Port": "5031" 11 | }, 12 | "HealthService": { 13 | "Name": "GrpcService", 14 | "IP": "localhost", 15 | "Port": "5021" 16 | }, 17 | "ConsulService": { 18 | "IP": "localhost", 19 | "Port": "8500" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Impl/DMS.GrpcConsul.Impl.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Impl/Entity/GrpcService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DMS.GrpcConsul.Impl.Entity 6 | { 7 | public class GrpcService 8 | { 9 | public string IP { get; set; } 10 | public int Port { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Impl/IRpcConfig.cs: -------------------------------------------------------------------------------- 1 | namespace DMS.GrpcConsul.Impl 2 | { 3 | public interface IRpcConfig 4 | { 5 | void Start(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Impl/RpcConfig.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Impl.RpcService; 2 | using DMS.GrpcConsul.Protocol; 3 | using Grpc.Core; 4 | using Microsoft.Extensions.Options; 5 | using System; 6 | 7 | namespace DMS.GrpcConsul.Impl 8 | { 9 | public class RpcConfig : IRpcConfig 10 | { 11 | private static Server _server; 12 | static IOptions GrpcSettings; 13 | 14 | public RpcConfig(IOptions grpcSettings) 15 | { 16 | GrpcSettings = grpcSettings; 17 | } 18 | 19 | public void Start() 20 | { 21 | _server = new Server 22 | { 23 | Services = { MsgService.BindService(new MsgServiceImpl()) }, 24 | Ports = { new ServerPort(GrpcSettings.Value.IP, GrpcSettings.Value.Port, ServerCredentials.Insecure) } 25 | }; 26 | _server.Start(); 27 | 28 | Console.WriteLine($"Grpc ServerListening On Port {GrpcSettings.Value.Port}"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Impl/RpcService/MsgServiceImpl.cs: -------------------------------------------------------------------------------- 1 | using DMS.GrpcConsul.Protocol; 2 | using Grpc.Core; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DMS.GrpcConsul.Impl.RpcService 9 | { 10 | public class MsgServiceImpl : MsgService.MsgServiceBase 11 | { 12 | public override async Task GetSum(GetMsgNumRequest request, ServerCallContext context) 13 | { 14 | return await Task.Run(() => 15 | { 16 | var result = new GetMsgSumReply(); 17 | 18 | result.Sum = request.Num1 + request.Num2; 19 | 20 | Console.WriteLine(request.Num1 + "+" + request.Num2 + "=" + result.Sum); 21 | 22 | return result; 23 | }); 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/DMS.GrpcConsul.Protocol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/Msg.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: msg.proto 4 | // 5 | #pragma warning disable 1591, 0612, 3021 6 | #region Designer generated code 7 | 8 | using pb = global::Google.Protobuf; 9 | using pbc = global::Google.Protobuf.Collections; 10 | using pbr = global::Google.Protobuf.Reflection; 11 | using scg = global::System.Collections.Generic; 12 | namespace DMS.GrpcConsul.Protocol { 13 | 14 | /// Holder for reflection information generated from msg.proto 15 | public static partial class MsgReflection { 16 | 17 | #region Descriptor 18 | /// File descriptor for msg.proto 19 | public static pbr::FileDescriptor Descriptor { 20 | get { return descriptor; } 21 | } 22 | private static pbr::FileDescriptor descriptor; 23 | 24 | static MsgReflection() { 25 | byte[] descriptorData = global::System.Convert.FromBase64String( 26 | string.Concat( 27 | "Cgltc2cucHJvdG8SF0RNUy5HcnBjQ29uc3VsLlByb3RvY29sIi4KEEdldE1z", 28 | "Z051bVJlcXVlc3QSDAoETnVtMRgBIAEoBRIMCgROdW0yGAIgASgFIh0KDkdl", 29 | "dE1zZ1N1bVJlcGx5EgsKA1N1bRgBIAEoBTJsCgpNc2dTZXJ2aWNlEl4KBkdl", 30 | "dFN1bRIpLkRNUy5HcnBjQ29uc3VsLlByb3RvY29sLkdldE1zZ051bVJlcXVl", 31 | "c3QaJy5ETVMuR3JwY0NvbnN1bC5Qcm90b2NvbC5HZXRNc2dTdW1SZXBseSIA", 32 | "YgZwcm90bzM=")); 33 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, 34 | new pbr::FileDescriptor[] { }, 35 | new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { 36 | new pbr::GeneratedClrTypeInfo(typeof(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest), global::DMS.GrpcConsul.Protocol.GetMsgNumRequest.Parser, new[]{ "Num1", "Num2" }, null, null, null), 37 | new pbr::GeneratedClrTypeInfo(typeof(global::DMS.GrpcConsul.Protocol.GetMsgSumReply), global::DMS.GrpcConsul.Protocol.GetMsgSumReply.Parser, new[]{ "Sum" }, null, null, null) 38 | })); 39 | } 40 | #endregion 41 | 42 | } 43 | #region Messages 44 | public sealed partial class GetMsgNumRequest : pb::IMessage { 45 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMsgNumRequest()); 46 | private pb::UnknownFieldSet _unknownFields; 47 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 48 | public static pb::MessageParser Parser { get { return _parser; } } 49 | 50 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 51 | public static pbr::MessageDescriptor Descriptor { 52 | get { return global::DMS.GrpcConsul.Protocol.MsgReflection.Descriptor.MessageTypes[0]; } 53 | } 54 | 55 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 56 | pbr::MessageDescriptor pb::IMessage.Descriptor { 57 | get { return Descriptor; } 58 | } 59 | 60 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 61 | public GetMsgNumRequest() { 62 | OnConstruction(); 63 | } 64 | 65 | partial void OnConstruction(); 66 | 67 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 68 | public GetMsgNumRequest(GetMsgNumRequest other) : this() { 69 | num1_ = other.num1_; 70 | num2_ = other.num2_; 71 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 72 | } 73 | 74 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 75 | public GetMsgNumRequest Clone() { 76 | return new GetMsgNumRequest(this); 77 | } 78 | 79 | /// Field number for the "Num1" field. 80 | public const int Num1FieldNumber = 1; 81 | private int num1_; 82 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 83 | public int Num1 { 84 | get { return num1_; } 85 | set { 86 | num1_ = value; 87 | } 88 | } 89 | 90 | /// Field number for the "Num2" field. 91 | public const int Num2FieldNumber = 2; 92 | private int num2_; 93 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 94 | public int Num2 { 95 | get { return num2_; } 96 | set { 97 | num2_ = value; 98 | } 99 | } 100 | 101 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 102 | public override bool Equals(object other) { 103 | return Equals(other as GetMsgNumRequest); 104 | } 105 | 106 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 107 | public bool Equals(GetMsgNumRequest other) { 108 | if (ReferenceEquals(other, null)) { 109 | return false; 110 | } 111 | if (ReferenceEquals(other, this)) { 112 | return true; 113 | } 114 | if (Num1 != other.Num1) return false; 115 | if (Num2 != other.Num2) return false; 116 | return Equals(_unknownFields, other._unknownFields); 117 | } 118 | 119 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 120 | public override int GetHashCode() { 121 | int hash = 1; 122 | if (Num1 != 0) hash ^= Num1.GetHashCode(); 123 | if (Num2 != 0) hash ^= Num2.GetHashCode(); 124 | if (_unknownFields != null) { 125 | hash ^= _unknownFields.GetHashCode(); 126 | } 127 | return hash; 128 | } 129 | 130 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 131 | public override string ToString() { 132 | return pb::JsonFormatter.ToDiagnosticString(this); 133 | } 134 | 135 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 136 | public void WriteTo(pb::CodedOutputStream output) { 137 | if (Num1 != 0) { 138 | output.WriteRawTag(8); 139 | output.WriteInt32(Num1); 140 | } 141 | if (Num2 != 0) { 142 | output.WriteRawTag(16); 143 | output.WriteInt32(Num2); 144 | } 145 | if (_unknownFields != null) { 146 | _unknownFields.WriteTo(output); 147 | } 148 | } 149 | 150 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 151 | public int CalculateSize() { 152 | int size = 0; 153 | if (Num1 != 0) { 154 | size += 1 + pb::CodedOutputStream.ComputeInt32Size(Num1); 155 | } 156 | if (Num2 != 0) { 157 | size += 1 + pb::CodedOutputStream.ComputeInt32Size(Num2); 158 | } 159 | if (_unknownFields != null) { 160 | size += _unknownFields.CalculateSize(); 161 | } 162 | return size; 163 | } 164 | 165 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 166 | public void MergeFrom(GetMsgNumRequest other) { 167 | if (other == null) { 168 | return; 169 | } 170 | if (other.Num1 != 0) { 171 | Num1 = other.Num1; 172 | } 173 | if (other.Num2 != 0) { 174 | Num2 = other.Num2; 175 | } 176 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 177 | } 178 | 179 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 180 | public void MergeFrom(pb::CodedInputStream input) { 181 | uint tag; 182 | while ((tag = input.ReadTag()) != 0) { 183 | switch(tag) { 184 | default: 185 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 186 | break; 187 | case 8: { 188 | Num1 = input.ReadInt32(); 189 | break; 190 | } 191 | case 16: { 192 | Num2 = input.ReadInt32(); 193 | break; 194 | } 195 | } 196 | } 197 | } 198 | 199 | } 200 | 201 | public sealed partial class GetMsgSumReply : pb::IMessage { 202 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMsgSumReply()); 203 | private pb::UnknownFieldSet _unknownFields; 204 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 205 | public static pb::MessageParser Parser { get { return _parser; } } 206 | 207 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 208 | public static pbr::MessageDescriptor Descriptor { 209 | get { return global::DMS.GrpcConsul.Protocol.MsgReflection.Descriptor.MessageTypes[1]; } 210 | } 211 | 212 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 213 | pbr::MessageDescriptor pb::IMessage.Descriptor { 214 | get { return Descriptor; } 215 | } 216 | 217 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 218 | public GetMsgSumReply() { 219 | OnConstruction(); 220 | } 221 | 222 | partial void OnConstruction(); 223 | 224 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 225 | public GetMsgSumReply(GetMsgSumReply other) : this() { 226 | sum_ = other.sum_; 227 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 228 | } 229 | 230 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 231 | public GetMsgSumReply Clone() { 232 | return new GetMsgSumReply(this); 233 | } 234 | 235 | /// Field number for the "Sum" field. 236 | public const int SumFieldNumber = 1; 237 | private int sum_; 238 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 239 | public int Sum { 240 | get { return sum_; } 241 | set { 242 | sum_ = value; 243 | } 244 | } 245 | 246 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 247 | public override bool Equals(object other) { 248 | return Equals(other as GetMsgSumReply); 249 | } 250 | 251 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 252 | public bool Equals(GetMsgSumReply other) { 253 | if (ReferenceEquals(other, null)) { 254 | return false; 255 | } 256 | if (ReferenceEquals(other, this)) { 257 | return true; 258 | } 259 | if (Sum != other.Sum) return false; 260 | return Equals(_unknownFields, other._unknownFields); 261 | } 262 | 263 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 264 | public override int GetHashCode() { 265 | int hash = 1; 266 | if (Sum != 0) hash ^= Sum.GetHashCode(); 267 | if (_unknownFields != null) { 268 | hash ^= _unknownFields.GetHashCode(); 269 | } 270 | return hash; 271 | } 272 | 273 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 274 | public override string ToString() { 275 | return pb::JsonFormatter.ToDiagnosticString(this); 276 | } 277 | 278 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 279 | public void WriteTo(pb::CodedOutputStream output) { 280 | if (Sum != 0) { 281 | output.WriteRawTag(8); 282 | output.WriteInt32(Sum); 283 | } 284 | if (_unknownFields != null) { 285 | _unknownFields.WriteTo(output); 286 | } 287 | } 288 | 289 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 290 | public int CalculateSize() { 291 | int size = 0; 292 | if (Sum != 0) { 293 | size += 1 + pb::CodedOutputStream.ComputeInt32Size(Sum); 294 | } 295 | if (_unknownFields != null) { 296 | size += _unknownFields.CalculateSize(); 297 | } 298 | return size; 299 | } 300 | 301 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 302 | public void MergeFrom(GetMsgSumReply other) { 303 | if (other == null) { 304 | return; 305 | } 306 | if (other.Sum != 0) { 307 | Sum = other.Sum; 308 | } 309 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 310 | } 311 | 312 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 313 | public void MergeFrom(pb::CodedInputStream input) { 314 | uint tag; 315 | while ((tag = input.ReadTag()) != 0) { 316 | switch(tag) { 317 | default: 318 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 319 | break; 320 | case 8: { 321 | Sum = input.ReadInt32(); 322 | break; 323 | } 324 | } 325 | } 326 | } 327 | 328 | } 329 | 330 | #endregion 331 | 332 | } 333 | 334 | #endregion Designer generated code 335 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/MsgGrpc.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: msg.proto 4 | // 5 | #pragma warning disable 0414, 1591 6 | #region Designer generated code 7 | 8 | using grpc = global::Grpc.Core; 9 | 10 | namespace DMS.GrpcConsul.Protocol { 11 | public static partial class MsgService 12 | { 13 | static readonly string __ServiceName = "DMS.GrpcConsul.Protocol.MsgService"; 14 | 15 | static readonly grpc::Marshaller __Marshaller_GetMsgNumRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::DMS.GrpcConsul.Protocol.GetMsgNumRequest.Parser.ParseFrom); 16 | static readonly grpc::Marshaller __Marshaller_GetMsgSumReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::DMS.GrpcConsul.Protocol.GetMsgSumReply.Parser.ParseFrom); 17 | 18 | static readonly grpc::Method __Method_GetSum = new grpc::Method( 19 | grpc::MethodType.Unary, 20 | __ServiceName, 21 | "GetSum", 22 | __Marshaller_GetMsgNumRequest, 23 | __Marshaller_GetMsgSumReply); 24 | 25 | /// Service descriptor 26 | public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor 27 | { 28 | get { return global::DMS.GrpcConsul.Protocol.MsgReflection.Descriptor.Services[0]; } 29 | } 30 | 31 | /// Base class for server-side implementations of MsgService 32 | public abstract partial class MsgServiceBase 33 | { 34 | public virtual global::System.Threading.Tasks.Task GetSum(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest request, grpc::ServerCallContext context) 35 | { 36 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); 37 | } 38 | 39 | } 40 | 41 | /// Client for MsgService 42 | public partial class MsgServiceClient : grpc::ClientBase 43 | { 44 | /// Creates a new client for MsgService 45 | /// The channel to use to make remote calls. 46 | public MsgServiceClient(grpc::Channel channel) : base(channel) 47 | { 48 | } 49 | /// Creates a new client for MsgService that uses a custom CallInvoker. 50 | /// The callInvoker to use to make remote calls. 51 | public MsgServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) 52 | { 53 | } 54 | /// Protected parameterless constructor to allow creation of test doubles. 55 | protected MsgServiceClient() : base() 56 | { 57 | } 58 | /// Protected constructor to allow creation of configured clients. 59 | /// The client configuration. 60 | protected MsgServiceClient(ClientBaseConfiguration configuration) : base(configuration) 61 | { 62 | } 63 | 64 | public virtual global::DMS.GrpcConsul.Protocol.GetMsgSumReply GetSum(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 65 | { 66 | return GetSum(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 67 | } 68 | public virtual global::DMS.GrpcConsul.Protocol.GetMsgSumReply GetSum(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest request, grpc::CallOptions options) 69 | { 70 | return CallInvoker.BlockingUnaryCall(__Method_GetSum, null, options, request); 71 | } 72 | public virtual grpc::AsyncUnaryCall GetSumAsync(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 73 | { 74 | return GetSumAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 75 | } 76 | public virtual grpc::AsyncUnaryCall GetSumAsync(global::DMS.GrpcConsul.Protocol.GetMsgNumRequest request, grpc::CallOptions options) 77 | { 78 | return CallInvoker.AsyncUnaryCall(__Method_GetSum, null, options, request); 79 | } 80 | /// Creates a new instance of client from given ClientBaseConfiguration. 81 | protected override MsgServiceClient NewInstance(ClientBaseConfiguration configuration) 82 | { 83 | return new MsgServiceClient(configuration); 84 | } 85 | } 86 | 87 | /// Creates service definition that can be registered with a server 88 | /// An object implementing the server-side handling logic. 89 | public static grpc::ServerServiceDefinition BindService(MsgServiceBase serviceImpl) 90 | { 91 | return grpc::ServerServiceDefinition.CreateBuilder() 92 | .AddMethod(__Method_GetSum, serviceImpl.GetSum).Build(); 93 | } 94 | 95 | } 96 | } 97 | #endregion 98 | -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/tools/ProtocGenerate.bat: -------------------------------------------------------------------------------- 1 | protoc -I . --csharp_out ../ --grpc_out ../ --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe msg.proto -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/tools/grpc_csharp_plugin.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/DMS.GrpcConsul.Protocol/tools/grpc_csharp_plugin.exe -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/tools/msg.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package DMS.GrpcConsul.Protocol; 4 | 5 | service MsgService{ 6 | rpc GetSum(GetMsgNumRequest) returns (GetMsgSumReply){} 7 | } 8 | 9 | message GetMsgNumRequest { 10 | int32 Num1 = 1; 11 | int32 Num2 = 2; 12 | } 13 | 14 | message GetMsgSumReply { 15 | int32 Sum = 1; 16 | } -------------------------------------------------------------------------------- /DMS.GrpcConsul.Protocol/tools/protoc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailang2ll/DMS.GrpcConsul/c8d777fcc57981205aa47c1ec0155dd4cec94731/DMS.GrpcConsul.Protocol/tools/protoc.exe -------------------------------------------------------------------------------- /DMS.GrpcConsul.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DMS.GrpcConsul.Hosting", "DMS.GrpcConsul.Hosting\DMS.GrpcConsul.Hosting.csproj", "{00E04F11-612A-48B7-A11C-126966999D8B}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DMS.GrpcConsul.Protocol", "DMS.GrpcConsul.Protocol\DMS.GrpcConsul.Protocol.csproj", "{F82219A2-1E7E-4E44-B27F-C64F138193FD}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DMS.GrpcConsul.Impl", "DMS.GrpcConsul.Impl\DMS.GrpcConsul.Impl.csproj", "{3DD722BE-0CE1-4E62-869D-96090D25A2C6}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMS.GrpcConsul.Client", "DMS.GrpcConsul.Client\DMS.GrpcConsul.Client.csproj", "{79736718-EA7A-40E3-A645-2C179E7C5C5F}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {00E04F11-612A-48B7-A11C-126966999D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {00E04F11-612A-48B7-A11C-126966999D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {00E04F11-612A-48B7-A11C-126966999D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {00E04F11-612A-48B7-A11C-126966999D8B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {F82219A2-1E7E-4E44-B27F-C64F138193FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {F82219A2-1E7E-4E44-B27F-C64F138193FD}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {F82219A2-1E7E-4E44-B27F-C64F138193FD}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {F82219A2-1E7E-4E44-B27F-C64F138193FD}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {3DD722BE-0CE1-4E62-869D-96090D25A2C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {3DD722BE-0CE1-4E62-869D-96090D25A2C6}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {3DD722BE-0CE1-4E62-869D-96090D25A2C6}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {3DD722BE-0CE1-4E62-869D-96090D25A2C6}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {79736718-EA7A-40E3-A645-2C179E7C5C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {79736718-EA7A-40E3-A645-2C179E7C5C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {79736718-EA7A-40E3-A645-2C179E7C5C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {79736718-EA7A-40E3-A645-2C179E7C5C5F}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {91F1851F-54C3-4EB1-AF25-9140323C7737} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DMS.GrpcConsul 2 | 3 | ### .net core实现Grpc通信,并实现Consul的服务注册,服务发现,健康检查,负载均衡 4 | qq交流群:18362376 5 | 6 |
7 | 8 | ## 一.博客地址实例 9 | .netcore consul实现服务注册与发现-单节点部署 10 | https://blog.csdn.net/hailang2ll/article/details/82020027 11 | 12 | .netcore consul实现服务注册与发现-集群完整版 13 | https://blog.csdn.net/hailang2ll/article/details/82079192 14 | 15 | 交流qq群:18362376 16 | 17 | --------------------------------------------------------------------------------