最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# HttpClient 如何使用 Consul 發(fā)現(xiàn)服務(wù)

 更新時(shí)間:2021年02月07日 10:53:26   作者:zhouandke  
這篇文章主要介紹了C# HttpClient 如何使用 Consul 發(fā)現(xiàn)服務(wù),幫助大家更好的理解和使用c#,感興趣的朋友可以了解下

  試用了Overt.Core.Grpc, 把 GRPC 的使用改造得像 WCF, 性能測(cè)試也非常不錯(cuò), 非常推薦各位使用.
  但已有項(xiàng)目大多是 http 請(qǐng)求, 改造成 GRPC 的話, 工作量比較大, 于是又找到了 Steeltoe.Discovery, 在 Startup 給 HttpClient 添加 DelegatingHandler, 動(dòng)態(tài)改變請(qǐng)求url中的 host 和 port, 將http請(qǐng)求指向consul 發(fā)現(xiàn)的服務(wù)實(shí)例, 這樣就實(shí)現(xiàn)了服務(wù)的動(dòng)態(tài)發(fā)現(xiàn).
  經(jīng)過性能測(cè)試, Steeltoe.Discovery 只有 Overt.Core.Grpc 的20%, 非常難以接受, 于是自己實(shí)現(xiàn)了一套基于 consul 的服務(wù)發(fā)現(xiàn)工具. 嗯, 名字好難取啊, 暫定為 ConsulDiscovery.HttpClient 吧
  功能很簡(jiǎn)單:

  1. webapi 從json中讀取配置信息 ConsulDiscoveryOptions;
  2. 如果自己是一個(gè)服務(wù), 則將自己注冊(cè)到consul中并設(shè)置健康檢查Url;
  3. ConsulDiscovery.HttpClient 內(nèi)有一個(gè)consul client 定時(shí)刷新所有服務(wù)的url訪問地址.

  比較核心的兩個(gè)類

using Consul;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace ConsulDiscovery.HttpClient
{
  public class DiscoveryClient : IDisposable
  {
    private readonly ConsulDiscoveryOptions consulDiscoveryOptions;
    private readonly Timer timer;
    private readonly ConsulClient consulClient;
    private readonly string serviceIdInConsul;

    public Dictionary<string, List<string>> AllServices { get; private set; } = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);


    public DiscoveryClient(IOptions<ConsulDiscoveryOptions> options)
    {
      consulDiscoveryOptions = options.Value;
      consulClient = new ConsulClient(x => x.Address = new Uri($"http://{consulDiscoveryOptions.ConsulServerSetting.IP}:{consulDiscoveryOptions.ConsulServerSetting.Port}"));
      timer = new Timer(Refresh);

      if (consulDiscoveryOptions.ServiceRegisterSetting != null)
      {
        serviceIdInConsul = Guid.NewGuid().ToString();
      }
    }

    public void Start()
    {
      var checkErrorMsg = CheckParams();
      if (checkErrorMsg != null)
      {
        throw new ArgumentException(checkErrorMsg);
      }
      RegisterToConsul();
      timer.Change(0, consulDiscoveryOptions.ConsulServerSetting.RefreshIntervalInMilliseconds);
    }

    public void Stop()
    {
      Dispose();
    }

    private string CheckParams()
    {
      if (string.IsNullOrWhiteSpace(consulDiscoveryOptions.ConsulServerSetting.IP))
      {
        return "Consul服務(wù)器地址 ConsulDiscoveryOptions.ConsulServerSetting.IP 不能為空";
      }

      if (consulDiscoveryOptions.ServiceRegisterSetting != null)
      {
        var registerSetting = consulDiscoveryOptions.ServiceRegisterSetting;
        if (string.IsNullOrWhiteSpace(registerSetting.ServiceName))
        {
          return "服務(wù)名稱 ConsulDiscoveryOptions.ServiceRegisterSetting.ServiceName 不能為空";
        }
        if (string.IsNullOrWhiteSpace(registerSetting.ServiceIP))
        {
          return "服務(wù)地址 ConsulDiscoveryOptions.ServiceRegisterSetting.ServiceIP 不能為空";
        }
      }
      return null;
    }

    private void RegisterToConsul()
    {
      if (string.IsNullOrEmpty(serviceIdInConsul))
      {
        return;
      }

      var registerSetting = consulDiscoveryOptions.ServiceRegisterSetting;
      var httpCheck = new AgentServiceCheck()
      {
        HTTP = $"{registerSetting.ServiceScheme}{Uri.SchemeDelimiter}{registerSetting.ServiceIP}:{registerSetting.ServicePort}/{registerSetting.HealthCheckRelativeUrl.TrimStart('/')}",
        Interval = TimeSpan.FromMilliseconds(registerSetting.HealthCheckIntervalInMilliseconds),
        Timeout = TimeSpan.FromMilliseconds(registerSetting.HealthCheckTimeOutInMilliseconds),
        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10),
      };
      var registration = new AgentServiceRegistration()
      {
        ID = serviceIdInConsul,
        Name = registerSetting.ServiceName,
        Address = registerSetting.ServiceIP,
        Port = registerSetting.ServicePort,
        Check = httpCheck,
        Meta = new Dictionary<string, string>() { ["scheme"] = registerSetting.ServiceScheme },
      };
      consulClient.Agent.ServiceRegister(registration).Wait();
    }

    private void DeregisterFromConsul()
    {
      if (string.IsNullOrEmpty(serviceIdInConsul))
      {
        return;
      }
      try
      {
        consulClient.Agent.ServiceDeregister(serviceIdInConsul).Wait();
      }
      catch
      { }
    }

    private void Refresh(object state)
    {
      Dictionary<string, AgentService>.ValueCollection serversInConsul;
      try
      {
        serversInConsul = consulClient.Agent.Services().Result.Response.Values;
      }
      catch // (Exception ex)
      {
        // 如果連接consul出錯(cuò), 則不更新服務(wù)列表. 繼續(xù)使用以前獲取到的服務(wù)列表
        // 但是如果很長(zhǎng)時(shí)間都不能連接consul, 服務(wù)列表里的一些實(shí)例已經(jīng)不可用了, 還一直提供這樣舊的列表也不合理, 所以要不要在這里實(shí)現(xiàn) 健康檢查? 這樣的話, 就得把檢查地址變成不能設(shè)置的
        return;
      }

      // 1. 更新服務(wù)列表
      // 2. 如果這個(gè)程序提供了服務(wù), 還要檢測(cè) 服務(wù)Id 是否在服務(wù)列表里
      var tempServices = new Dictionary<string, HashSet<string>>();
      bool needReregisterToConsul = true;
      foreach (var service in serversInConsul)
      {
        var serviceName = service.Service;
        if (!service.Meta.TryGetValue("scheme", out var serviceScheme))
        {
          serviceScheme = Uri.UriSchemeHttp;
        }
        var serviceHost = $"{serviceScheme}{Uri.SchemeDelimiter}{service.Address}:{service.Port}";
        if (!tempServices.TryGetValue(serviceName, out var serviceHosts))
        {
          serviceHosts = new HashSet<string>();
          tempServices[serviceName] = serviceHosts;
        }
        serviceHosts.Add(serviceHost);

        if (needReregisterToConsul && !string.IsNullOrEmpty(serviceIdInConsul) && serviceIdInConsul == service.ID)
        {
          needReregisterToConsul = false;
        }
      }

      if (needReregisterToConsul)
      {
        RegisterToConsul();
      }

      var tempAllServices = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
      foreach (var item in tempServices)
      {
        tempAllServices[item.Key] = item.Value.ToList();
      }
      AllServices = tempAllServices;
    }


    public void Dispose()
    {
      DeregisterFromConsul();
      consulClient.Dispose();
      timer.Dispose();
    }
  }
}
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace ConsulDiscovery.HttpClient
{
  public class DiscoveryHttpMessageHandler : DelegatingHandler
  {
    private static readonly Random random = new Random((int)DateTime.Now.Ticks);

    private readonly DiscoveryClient discoveryClient;

    public DiscoveryHttpMessageHandler(DiscoveryClient discoveryClient)
    {
      this.discoveryClient = discoveryClient;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
      if (discoveryClient.AllServices.TryGetValue(request.RequestUri.Host, out var serviceHosts))
      {
        if (serviceHosts.Count > 0)
        {
          var index = random.Next(serviceHosts.Count);
          request.RequestUri = new Uri(new Uri(serviceHosts[index]), request.RequestUri.PathAndQuery);
        }
      }
      return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
    }
  }
}

  使用方法

  為了簡(jiǎn)單, 我為新建的WebApi 增加了一個(gè) HelloController, 提供 SayHelloService 服務(wù), 并把自己注冊(cè)到Consul.

  當(dāng)我們?cè)L問這個(gè)WebApi的 /WeatherForecast 時(shí), 其Get()方法會(huì)訪問 http://SayHelloService/Hello/NetCore, 這就相當(dāng)于一次遠(yuǎn)程調(diào)用, 只是調(diào)用的就是這個(gè)WebApi的/Hello/NetCore

  1. appsettings.json 增加

"ConsulDiscoveryOptions": {
  "ConsulServerSetting": {
   "IP": "127.0.0.1", // 必填
   "Port": 8500, // 必填
   "RefreshIntervalInMilliseconds": 1000
  },
  "ServiceRegisterSetting": {
   "ServiceName": "SayHelloService", // 必填
   "ServiceIP": "127.0.0.1", // 必填
   "ServicePort": 5000, // 必填
   "ServiceScheme": "http", // 只能是http 或者 https, 默認(rèn)http, 
   "HealthCheckRelativeUrl": "/HealthCheck",
   "HealthCheckIntervalInMilliseconds": 500,
   "HealthCheckTimeOutInMilliseconds": 2000
  }
 }

  2.修改Startup.cs

using ConsulDiscovery.HttpClient;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;

namespace WebApplication1
{
  public class Startup
  {
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddControllers();

      // 注冊(cè) ConsulDiscovery 相關(guān)配置
      services.AddConsulDiscovery(Configuration);
      // 配置 SayHelloService 的HttpClient
      services.AddHttpClient("SayHelloService", c =>
        {
          c.BaseAddress = new Uri("http://SayHelloService");
        })
        .AddHttpMessageHandler<DiscoveryHttpMessageHandler>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
    {
      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }

      app.UseRouting();

      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapControllers();
      });

      // 啟動(dòng) ConsulDiscovery
      app.StartConsulDiscovery(lifetime);
    }
  }
}

  3. 添加 HelloController

using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers
{
  [ApiController]
  [Route("[controller]")]
  public class HelloController : ControllerBase
  {
    [HttpGet]
    [Route("{name}")]
    public string Get(string name)
    {
      return $"Hello {name}";
    }
  }
}

  4. 修改WeatherForecast

using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using System.Threading.Tasks;

namespace WebApplication1.Controllers
{
  [ApiController]
  [Route("[controller]")]
  public class WeatherForecastController : ControllerBase
  {
    private readonly IHttpClientFactory httpClientFactory;

    public WeatherForecastController(IHttpClientFactory httpClientFactory)
    {
      this.httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    public async Task<string> Get()
    {
      var httpClient = httpClientFactory.CreateClient("SayHelloService");
      var result = await httpClient.GetStringAsync("Hello/NetCore");
      return $"WeatherForecast return:      {result}";
    }
  }
}

  5. 啟動(dòng)consul

consul agent -dev

  6. 啟動(dòng) WebApplication1 并訪問 http://localhost:5000/weatherforecast

  以上示例可以到 https://github.com/zhouandke/ConsulDiscovery.HttpClient 下載, 請(qǐng)記住一定要 啟動(dòng)consul:    consul agent -dev

  End

以上就是C# HttpClient 如何使用 Consul 發(fā)現(xiàn)服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于C# HttpClient使用 Consul 發(fā)現(xiàn)服務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#中讀寫INI文件的方法例子

    C#中讀寫INI文件的方法例子

    C#中讀寫INI文件的方法例子,需要的朋友可以參考一下
    2013-05-05
  • C#實(shí)現(xiàn)線性查找算法

    C#實(shí)現(xiàn)線性查找算法

    這篇文章介紹了C#實(shí)現(xiàn)線性查找的算法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • C#使用Unity實(shí)現(xiàn)剪刀石頭布游戲

    C#使用Unity實(shí)現(xiàn)剪刀石頭布游戲

    這篇文章主要為大家詳細(xì)介紹了C#語言使用Unity實(shí)現(xiàn)剪刀石頭布游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • C#如何獲取計(jì)算機(jī)信息

    C#如何獲取計(jì)算機(jī)信息

    這篇文章主要為大家詳細(xì)介紹了C#獲取計(jì)算機(jī)信息的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C# OCR實(shí)現(xiàn)文字識(shí)別功能

    C# OCR實(shí)現(xiàn)文字識(shí)別功能

    OCR,中文叫做光學(xué)字符識(shí)別。它是利用光學(xué)技術(shù)和計(jì)算機(jī)技術(shù)把印在或?qū)懺诩埳系奈淖肿x取出來,并轉(zhuǎn)換成一種計(jì)算機(jī)能夠接受、人又可以理解的格式。本文將利用OCR實(shí)現(xiàn)文字識(shí)別功能,感興趣的可以了解一下
    2022-11-11
  • c#中實(shí)現(xiàn)圖片灰度化技術(shù)詳解

    c#中實(shí)現(xiàn)圖片灰度化技術(shù)詳解

    這篇文章主要介紹了c#中實(shí)現(xiàn)圖片灰度化技術(shù)詳解,本文給出計(jì)算公式和實(shí)現(xiàn)代碼以及圖片例子,需要的朋友可以參考下
    2014-08-08
  • 詳解如何使用C#獲取計(jì)算機(jī)信息

    詳解如何使用C#獲取計(jì)算機(jī)信息

    這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)獲取計(jì)算機(jī)信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下
    2024-10-10
  • C#中Mutex對(duì)象用法分析

    C#中Mutex對(duì)象用法分析

    這篇文章主要介紹了C#中Mutex對(duì)象用法,結(jié)合實(shí)例形式分析了Mutex對(duì)象的功能與線程操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • C#利用FileSystemWatcher實(shí)時(shí)監(jiān)控文件的增加,修改,重命名和刪除

    C#利用FileSystemWatcher實(shí)時(shí)監(jiān)控文件的增加,修改,重命名和刪除

    好多時(shí)候,我們都需要知道某些目錄下的文件什么時(shí)候被修改、刪除過等。本文將利用FileSystemWatcher實(shí)現(xiàn)實(shí)時(shí)監(jiān)控文件的增加,修改,重命名和刪除,感興趣的可以了解一下
    2022-08-08
  • C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(4)

    C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(4)

    這篇文章主要介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì),學(xué)習(xí)內(nèi)容是總結(jié)銷售信息的保存以及加載銷售信息,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-11-11

最新評(píng)論

温泉县| 五家渠市| 庆安县| 华亭县| 十堰市| 南漳县| 武隆县| 邮箱| 大安市| 鹤壁市| 连平县| 大埔区| 红河县| 仪陇县| 兰考县| 民乐县| 增城市| 渝中区| 城步| 宁晋县| 财经| 泗洪县| 桐柏县| 巴彦县| 闻喜县| 秀山| 礼泉县| 渝北区| 临泽县| 鹤岗市| 鹤壁市| 雷波县| 高唐县| 开原市| 洛浦县| 信宜市| 麟游县| 巩留县| 中西区| 玛曲县| 新密市|