根据上一篇Consul服务的注册和发现,那么客户端如何去访问我们的Consul服务?其实客户端访问Consul实际上是访问Consul的服务实例。客户端自己可以实现对Consul服务实例的轮训,每次刷新端口都会发生改变,由于客户端访问Consul采用的轮训策略,所以每次刷新Consul的服务实例都会发生改变。
下面就直接上客户端访问Consul服务实例的代码:
using System; using System.Collections.Generic; using System.Text; namespace Demo { /// <summary> /// 用户服务的接口定义。 /// </summary> public interface IUserService { /// <summary> /// 查找指定主键的用户实例对象。 /// </summary> /// <param name="id">用户的主键。</param> /// <returns>返回查找到的用户实例对象。</returns> User FindUser(int id); /// <summary> /// 获取所有用户的实例集合。 /// </summary> /// <returns>返回所有的用户实例。</returns> IEnumerable<User> UserAll(); } }
using System; using System.Collections.Generic; using System.Text; namespace Demo { /// <summary> /// 用户模型。 /// </summary> public class User { /// <summary> /// 获取或者设置用户主键。 /// </summary> public int ID { get; set; } /// <summary> /// 获取或者设置用户姓名。 /// </summary> public string Name { get; set; } /// <summary> /// 获取或者设置用户账号名称。 /// </summary> public string Account { get; set; } /// <summary> /// 获取或者设置用户密码。 /// </summary> public string Password { get; set; } /// <summary> /// 获取或者设置用户的电子邮箱地址。 /// </summary> public string Email { get; set; } /// <summary> /// 获取或者设置用户角色。 /// </summary> public string Role { get; set; } /// <summary> /// 获取或者设置用户的登录时间。 /// </summary> public DateTime LoginTime { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Demo { /// <summary> /// 实现用户服务接口的实现类型。 /// </summary> public class UserService : IUserService { private IList<User> dataList; /// <summary> /// 初始化类型的实例 /// </summary> public UserService() { dataList = new List<User>() { new User {ID=1,Name="张三",Account="5435435345",Password="4535435435",Email="4535345345", Role="Admin", LoginTime=DateTime.Now}, new User {ID=2,Name="李四",Account="5435435345",Password="5435345345",Email="543534535", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) }, new User { ID = 3, Name = "王二", Account = "45354", Password = "3245345", Email = "54353455", Role = "Admin", LoginTime = DateTime.Now.AddDays(-30) }, new User { ID = 4, Name = "麻子", Account = "45354", Password = "4534535", Email = "453534534", Role = "Admin", LoginTime = DateTime.Now.AddDays(-90) }, new User { ID = 5, Name = "陈五", Account = "54353", Password = "5435345", Email = "5435345345", Role = "Admin", LoginTime = DateTime.Now.AddMinutes(-50) } }; } /// <summary> /// 查找指定主键的用户实例对象。 /// </summary> /// <param name="id">用户的主键。</param> /// <returns>返回查找到的用户实例对象。</returns> public User FindUser(int id) { return dataList.FirstOrDefault(user => user.ID == id); } /// <summary> /// 获取所有用户的实例集合。 /// </summary> /// <returns>返回所有的用户实例。</returns> public IEnumerable<User> UserAll() { return dataList; } } }
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using ConsulDemo.Models; using Microsoft.Extensions.Logging; using Demo; using Consul; using System.Net.Http; namespace ConsulDemo.Controllers { public class HomeController : Controller { private readonly ILogger<HomeController> _logger; private readonly IUserService _userService; private static int index; /// <summary> /// 初始化该类型的新实例。 /// </summary> /// <param name="logger">注入日志对象。</param> /// <param name="userService">注入用户服务对象。</param> public HomeController(ILogger<HomeController> logger, IUserService userService) { _logger = logger; _userService = userService; } /// <summary> /// 首页。 /// </summary> /// <returns></returns> public IActionResult Index() { #region 分布式架构 #region 通过 Consul 服务发现来执行服务实例。 //发现服务 string url = "http://PatrickLiuService/api/users/all"; ConsulClient client = new ConsulClient(config => { config.Address = new Uri("http://localhost:8500/"); config.Datacenter = "dc1"; }); var response = client.Agent.Services().Result.Response; foreach (var item in response) { Console.WriteLine("*************************************************************"); Console.WriteLine(item.Key); var service = item.Value; Console.WriteLine($"{service.Address}--{service.Port}--{service.Service}"); Console.WriteLine("*************************************************************"); } Uri uri = new Uri(url); string groupName = uri.Host; AgentService agentService = null; var serviceDirectory = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase)).ToArray(); //{//1、 写死的 // agentService = serviceDirectory[0].Value; //} { //2、轮询 if (index >= 10000) { index = 0; } agentService = serviceDirectory[index++ % serviceDirectory.Length].Value; } // {//3、随机 // var indexResult = new Random(index++).Next(0, serviceDirectory.Length); // agentService = serviceDirectory[indexResult].Value; //} url = $"{uri.Scheme}://{agentService.Address}:{agentService.Port}{uri.PathAndQuery}"; #endregion string content = InvokeAPI(url); this.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content); Console.WriteLine($"This is {url} Invoke."); #endregion return View(); } /// <summary> /// 封装 HttpClient 实例,提供 Http 调用。 /// </summary> /// <param name="url">http url 的地址。</param> /// <returns>返回结束数据,格式:JSON。</returns> public static string InvokeAPI(string url) { using (HttpClient client = new HttpClient()) { HttpRequestMessage message = new HttpRequestMessage(); message.Method = HttpMethod.Get; message.RequestUri = new Uri(url); var result = client.SendAsync(message).Result; string conent = result.Content.ReadAsStringAsync().Result; return conent; } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Demo; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace ConsulDemo { 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<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddSingleton<IUserService, UserService>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
启动Consul:
Consul启动命令:Consul agent –dev
启动5个服务实例端口分别为:1000,2000,3000,4000,5000
Consul实例:
然后启动客户端,访问Consul服务实例:
第一次启动:端口1000
第一次刷新端口为:2000
第二次刷新端口为:3000
目前为止 虽然可以自由的发现新服务,也可以发现失败的服务,实现了服务的自动注册和发现,但是Consul另外一个问题就是,客户端使用太麻烦,我们需要自己去决定调用服务策略,是轮训、随机、权重,还是其他策略,如果项目很小不是问题,如果项目很大,需求变化很快,我们都需要手动去做这些事,就太浪费时间和精力了。