本系列編寫目的純屬我的開發記錄 如下代碼均爲demo級 若有須要 請自行優化 代碼完整包因爲公司電腦加密 沒法上傳整包的demo文件html
consul 下載地址 : https://www.consul.io/downloads.htmljson
此處使用windows 64版本 windows
爲方便使用在建立一個bat文件 命令以下:api
cd C:\Users\Lenovo\Desktop\
consul.exe agent -devapp
第一行爲進入桌面dom
第二行爲 執行consul開發模式tcp
運行後可在 localhost:8500 地址處看到consul 後臺服務管理頁面ide
因爲 使用了consul 最新nuget包 因此 在建立的時候須要使用 .netcore 2.1 微服務
因爲已經搭建了demo1 這裏演示截圖會是demo2 建立方式同樣oop
建立一個core 2.1的API空項目
建立一個BaseController 用來保存配置信息
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace DemoApi_I.Controllers { public class BaseController : ControllerBase { public static Setting Config; public BaseController(IOptions<Setting> setting) { Config = setting.Value; } } }
再添加一個健康檢查的控制器
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace DemoApi_II.Controllers { [Route("api/[controller]")] public class HealthController : BaseController { public HealthController(IOptions<Setting> setting) : base(setting) { } // GET api/values [HttpGet] public string Get() { return "ok"; } } }
爲了統一顯示 能夠更改默認values控制器爲
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace DemoApi_II.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController : BaseController { public ValuesController(IOptions<Setting> setting) : base(setting) { } // GET api/values [HttpGet] public string Get() { var aaa = Config.ServiceName; return "二號測試API"; } } }
接下來 增長 一個配置類
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace DemoApi_II { public class Setting { /// <summary> /// 端口號 /// </summary> public int Port { get; set; } /// <summary> /// 服務名稱 /// </summary> public string ServiceName { get; set; } /// <summary> /// 服務發現IP /// </summary> public string ConsulIP { get; set; } /// <summary> /// 服務發現端口號 /// </summary> public int ConsulPort { get; set; } } }
在appsettings.json 內新增節點
測試地址中只須要改端口號和服務名稱便可 會自動讀取本機ip到注入到consul中
"Setting": { "Port": "1001", "ServiceName": "demoAPi", "ConsulIP": "localhost", "ConsulPort": "8500" }
注意 須要修改成 始終複製或者較新複製
修改 Program.cs
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace DemoApi_II { public class Program { public static string StartPort; public static void Main(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true) .Build(); StartPort = config.GetSection("Setting")["Port"]; CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseUrls($"http://*:{StartPort}") .UseStartup<Startup>(); } }
修改startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ConsulRegisterHelper; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace DemoApi_II { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<Setting>(Configuration.GetSection("Setting")); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); app.RegisterConsul(lifetime, new ServiceEntity { IP = NetworkHelper.LocalIPAddress, Port = Convert.ToInt32(Configuration.GetSection("Setting")["Port"]), ServiceName = Configuration.GetSection("Setting")["ServiceName"], ConsulIP = Configuration.GetSection("Setting")["ConsulIP"], ConsulPort = Convert.ToInt32(Configuration.GetSection("Setting")["ConsulPort"]) }); } } }
建立自動注入consul服務的類庫
新建core2.1類庫項目 取名ConsulRegisterHelper
將如下3個類建立便可
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace ConsulRegisterHelper { public class NetworkHelper { public static string LocalIPAddress { get { UnicastIPAddressInformation mostSuitableIp = null; var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (var network in networkInterfaces) { if (network.OperationalStatus != OperationalStatus.Up) continue; var properties = network.GetIPProperties(); if (properties.GatewayAddresses.Count == 0) continue; foreach (var address in properties.UnicastAddresses) { if (address.Address.AddressFamily != AddressFamily.InterNetwork) continue; if (IPAddress.IsLoopback(address.Address)) continue; return address.Address.ToString(); } } return mostSuitableIp != null ? mostSuitableIp.Address.ToString() : ""; } } public static int GetRandomAvaliablePort(int minPort = 1024, int maxPort = 65535) { Random rand = new Random(); while (true) { int port = rand.Next(minPort, maxPort); if (!IsPortInUsed(port)) { return port; } } } private static bool IsPortInUsed(int port) { IPGlobalProperties ipGlobalProps = IPGlobalProperties.GetIPGlobalProperties(); IPEndPoint[] ipsTCP = ipGlobalProps.GetActiveTcpListeners(); if (ipsTCP.Any(p => p.Port == port)) { return true; } IPEndPoint[] ipsUDP = ipGlobalProps.GetActiveUdpListeners(); if (ipsUDP.Any(p => p.Port == port)) { return true; } TcpConnectionInformation[] tcpConnInfos = ipGlobalProps.GetActiveTcpConnections(); if (tcpConnInfos.Any(conn => conn.LocalEndPoint.Port == port)) { return true; } return false; } } }
using Consul; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using System; namespace ConsulRegisterHelper { public static class AppBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity) { var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//請求註冊的 Consul 地址 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啓動多久後註冊 Interval = TimeSpan.FromSeconds(3),//健康檢查時間間隔,或者稱爲心跳間隔 HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}{serviceEntity.HealthUrl}",//健康檢查地址 Timeout = TimeSpan.FromSeconds(3) }; // Register service with consul var registration = new AgentServiceRegistration() { Checks = new[] { httpCheck }, ID = Guid.NewGuid().ToString(), Name = serviceEntity.ServiceName, Address = serviceEntity.IP, Port = serviceEntity.Port, Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 標籤,以便 Fabio 識別 }; consulClient.Agent.ServiceRegister(registration).Wait();//服務啓動時註冊,內部實現其實就是使用 Consul API 進行註冊(HttpClient發起) lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服務中止時取消註冊 }); return app; } } }
using System; using System.Collections.Generic; using System.Text; namespace ConsulRegisterHelper { public class ServiceEntity { public ServiceEntity() { HealthUrl = "/api/health"; } /// <summary> /// 服務IP /// </summary> public string IP { get; set; } /// <summary> /// 服務端口號 /// </summary> public int Port { get; set; } /// <summary> /// 服務名稱 /// </summary> public string ServiceName { get; set; } /// <summary> /// 服務發現地址 /// </summary> public string ConsulIP { get; set; } /// <summary> /// 服務發現端口號 /// </summary> public int ConsulPort { get; set; } /// <summary> /// 健康檢查地址默認爲/api/health /// </summary> public string HealthUrl { get; set; } } }
在須要注入的服務Startup.cs中經過以下代碼注入:
建立bat文件方便測試使用
E: cd E:\ServerApi\OcelotGetWay\DemoApi_II\bin\Debug\netcoreapp2.1 dotnet DemoApi_II.dll
到此 測試demoapi 準備完成
參考內容:
微服務系列文章
https://www.cnblogs.com/edisonchou/p/dotnetcore_microservice_foundation_blogs_index_final.html
ocelot配置特性介紹
https://blog.csdn.net/qin_yu_2010/article/details/82749414