.Net8.0
及以上版本,微软官方提供了服务发现Nuget
包Microsoft.Extensions.ServiceDiscovery
,能够对 HttpClient
请求服务进行服务发现和解析,对于轻量级Flurl.Http
来说,也可以进行集成,主要思路是通过HttpClientFactory
构建HttpClient
实例,调用new FlurlClient(httpClientFactory.CreateClient())
实现,以下具体介绍集成过程同时与常规的 HttpClient
写法做一个比较。
服务发现
引入依赖包
Microsoft.Extensions.ServiceDiscovery
当前对应版本为9.0.0
。可以通过Nuget
管理器引入到项目中。
dotnet nuget add pack Microsoft.Extensions.ServiceDiscovery
基础配置服务
主类中主体结构如下:
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// 注册服务
IServiceCollection services = builder.Services;
// 添加服务发现
services.AddServiceDiscovery();
// 设置httpclient构建添加服务发现
services.ConfigureHttpClientDefaults(static http =>
{
// Turn on service discovery by default
http.AddServiceDiscovery();
});
// 注册请求服务
services.AddSingleton<MapClientService>();
var app = builder.Build();
app.MapControllers();
app.Run();
}
其中,AddServiceDiscovery()
注册服务发现。
builder.Services.AddServiceDiscovery();
MapClientService
实际请求处理类。
// 注册请求服务
services.AddSingleton<MapClientService>();
ConfigureHttpClientDefaults(static http =>{})
添加全局HttpClient
实例应用服务发现。
// 设置httpclient构建添加服务发现
services.ConfigureHttpClientDefaults(static http =>
{
// Turn on service discovery by default
http.AddServiceDiscovery();
});
添加服务发现配置appsettings.json
根层级。
{
"Services": {
"mapservice": { // 服务名称
"http": [ // http请求
"192.168.31.116:6003" // 服务实际服务地址和端口
]
}
}
}
请求实现类
普通工厂创建实例
private readonly MapOptions _options;
private readonly IDistributedCache _cache;
private readonly IHttpClientFactory _httpClientFactory;
public MapClientService(IOptions<MapOptions> map,IDistributedCache cache,IHttpClientFactory httpClientFactory)
{
_options = map?.Value;
_cache = cache;
_httpClientFactory = httpClientFactory;
}
// 请求服务地址(期望通过服务发现进行解析)
private const string _url = "http://mapservice";
public const string token = "/api/identity/token";
public async Task<string> Token()
{
string key = _cache.GetString(token);
if (key == null) {
var data = new
{
grantType = "password",
account = _options.Uname,
password = _options.Pwd
};
// 构建请求--------------------------------------------------
HttpClient httpClient = _httpClientFactory.CreateClient();
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.Method = HttpMethod.Post;
httpRequest.RequestUri = new Uri($"{_url}{updateMapState}");
httpRequest.Content = new StringContent(JsonSerializer.Serialize(data));
httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequest);
var msg = await httpResponse.Content.ReadAsStringAsync();
AjaxResult<TokenResult> result = JsonSerializer.Deserialize<AjaxResult<TokenResult>>(msg);
if (result.Type == 200)
{
key = result.Data.AccessToken;
_cache.SetString(token, key,new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300)});
}
}
return key;
}
运行输入日志如下:
info: System.Net.Http.HttpClient.Default.LogicalHandler[100]
Start processing HTTP request POST http://mapservice/api/urlmap/updateurlmapstate
info: System.Net.Http.HttpClient.Default.ClientHandler[100]
Sending HTTP request POST http://192.168.31.116:6003/api/urlmap/updateurlmapstate
使用Flurl.Http
请求
直接使用Flurl.Http
对之前的HttpClientFactory
进行改造。
using Flurl.Http;
private readonly MapOptions _options;
private readonly IDistributedCache _cache;
private readonly IFlurlClient _flurlClient;
public MapClientService(IOptions<MapOptions> map,IDistributedCache cache)
{
_options = map?.Value;
_cache = cache;
}
// 请求服务地址(期望通过服务发现进行解析)
private const string _url = "http://mapservice";
public const string token = "/api/identity/token";
public async Task<string> Token()
{
string key = _cache.GetString(token);
if (key == null) {
var data = new
{
grantType = "password",
account = _options.Uname,
password = _options.Pwd
};
// 构建请求--------------------------------------------------
var result = await $"{_url}{token}".PostJsonAsync(data).ReceiveJson<AjaxResult<TokenResult>>();
if (result.Type == 200)
{
key = result.Data.AccessToken;
_cache.SetString(token, key,new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300)});
}
}
return key;
}
通过FlurlClient
并支持服务发现
private readonly MapOptions _options;
private readonly IDistributedCache _cache;
private readonly IFlurlClient _flurlClient;
public MapClientService(IOptions<MapOptions> map,IDistributedCache cache,IHttpClientFactory httpClientFactory)
{
_options = map?.Value;
_cache = cache;
_flurlClient = new FlurlClient(httpClientFactory.CreateClient());
}
// 请求服务地址(期望通过服务发现进行解析)
private const string _url = "http://mapservice";
public const string token = "/api/identity/token";
public async Task<string> Token()
{
string key = _cache.GetString(token);
if (key == null) {
var data = new
{
grantType = "password",
account = _options.Uname,
password = _options.Pwd
};
// 构建请求--------------------------------------------------
var result = await _flurlClient.Request($"{_url}{token}").PostJsonAsync(data).ReceiveJson<AjaxResult<TokenResult>>();
if (result.Type == 200)
{
key = result.Data.AccessToken;
_cache.SetString(token, key,new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300)});
}
}
return key;
}
运行项目,程序输入如下,与HttpClientFactory
构建实例发起请求输出一致。
info: System.Net.Http.HttpClient.Default.LogicalHandler[100]
Start processing HTTP request POST http://mapservice/api/identity/token2
info: System.Net.Http.HttpClient.Default.ClientHandler[100]
Sending HTTP request POST http://192.168.31.116:6003/api/identity/token2
可以发现,对应请求日志输出,两者并无差异,也能够成功解析,表示通过IHttpClientFactory
构建实例能够与Flurl.Http
中进行集成。既简化了简单的接口请求,又能够使用HttpClient
官方提供的一些扩展功能。