C\#HttpClient 는 Consult 발견 서 비 스 를 어떻게 사용 합 니까?
13303 단어 C#HttpClientConsul발견 서비스
그러나 기 존 프로젝트 는 대부분 http 요청 이 었 습 니 다.GRPC 로 개조 하면 작업량 이 많 았 습 니 다.그래서 Steeltoe.Discovery 를 찾 았 습 니 다.Startup 에서 HttpClient 에 Delegating Handler 를 추가 하고 요청 url 의 host 와 port 를 동적 으로 변경 하여 http 요청 을 consul 이 발견 한 서비스 사례 를 가리 키 면 서비스의 동적 발견 을 실현 할 수 있 습 니 다.
성능 테스트 를 통 해 Steeltoe.Discovery 는 Overt.Core.Grpc 의 20%밖 에 되 지 않 아 받 아들 이기 가 매우 어 려 웠 습 니 다.그래서 자신 은 consul 기반 서비스 발견 도 구 를 실 현 했 습 니 다.네,이름 이 너무 어렵 습 니 다.ConsultDiscovery.HttpClient 로 잠 정적 으로 정 하 세 요.
기능 은 매우 간단 하 다.
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 ConsulDiscoveryOptions.ConsulServerSetting.IP ";
}
if (consulDiscoveryOptions.ServiceRegisterSetting != null)
{
var registerSetting = consulDiscoveryOptions.ServiceRegisterSetting;
if (string.IsNullOrWhiteSpace(registerSetting.ServiceName))
{
return " ConsulDiscoveryOptions.ServiceRegisterSetting.ServiceName ";
}
if (string.IsNullOrWhiteSpace(registerSetting.ServiceIP))
{
return " 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 , .
// consul, , , ? ,
return;
}
// 1.
// 2. , Id
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);
}
}
}
사용 방법간단 하기 위해 서 나 는 새로 만 든 WebApi 에 하 나 를 추가 했다. Hello Controller,Say Hello 서비스 서 비 스 를 제공 하고 자신 을 Consul 에 등록 합 니 다.
우리 가 이 WebApi 의/Weather Forecast 를 방문 할 때,Get()방법 은http://SayHelloService/Hello/NetCore에 접근 합 니 다.이것 은 원 격 호출 에 해당 합 니 다.다만 이 WebApi 의/Hello/NetCore 를 호출 합 니 다.
1. apptsettings.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, 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();
// ConsulDiscovery
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();
});
// 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.일기 예보 수정
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.consul 시작
consul agent -dev
6.웹 애플 리 케 이 션 1 을 시작 하고 접근 http://localhost:5000/weatherforecast 이상 의 예 는 도착 할 수 있다 https://github.com/zhouandke/ConsulDiscovery.HttpClient 다운로드 consul 시작:
consul agent -dev
End이상 은 C\#HttpClient 가 Consul 발견 서 비 스 를 어떻게 사용 하 는 지 에 대한 상세 한 내용 입 니 다.C\#HttpClient 가 Consul 발견 서 비 스 를 사용 하 는 지 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
WebView2를 Visual Studio 2017 Express에서 사용할 수 있을 때까지Evergreen .Net Framework SDK 4.8 VisualStudio2017에서 NuGet을 사용하기 때문에 패키지 관리 방법을 packages.config 대신 PackageReference를 사용해야...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.