.NET Core 3.0之創(chuàng)建基于Consul的Configuration擴(kuò)展組件
經(jīng)過(guò)前面三篇關(guān)于.NET Core Configuration的文章之后,本篇文章主要討論如何擴(kuò)展一個(gè)Configuration組件出來(lái)。
了解了Configuration的源碼后,再去擴(kuò)展一個(gè)組件就會(huì)比較簡(jiǎn)單,接下來(lái)我們將在.NET Core 3.0-preview5的基礎(chǔ)上創(chuàng)建一個(gè)基于Consul的配置組件。
相信大家對(duì)Consul已經(jīng)比較了解了,很多項(xiàng)目都會(huì)使用Consul作為配置中心,此處也不做其他闡述了,主要是講一下,創(chuàng)建Consul配置擴(kuò)展的一些思路。使用Consul配置功能時(shí),我們可以將信息轉(zhuǎn)成JSON格式后再存儲(chǔ),那么我們?cè)谧x取的時(shí)候,在體驗(yàn)上就像是從讀取JSON文件中讀取一樣。
開(kāi)發(fā)前的準(zhǔn)備初始化Consul
假設(shè)你已經(jīng)安裝并啟動(dòng)了Consul,我們打開(kāi)Key/Value功能界面,創(chuàng)建兩組配置選項(xiàng)出來(lái),分別是commonservice和userservice,如下圖所示
配置值采用JSON格式
實(shí)現(xiàn)思路
我們知道在Configuration整個(gè)的設(shè)計(jì)框架里,比較重要的類(lèi)ConfigurationRoot,內(nèi)部又有一個(gè)IConfigurationProvider集合屬性,也就是說(shuō)我們追加IConfigurationProvider實(shí)例最終也會(huì)被放到到該集合中,如下圖所示
該項(xiàng)目中,我使用到了一個(gè)已經(jīng)封裝好的Consul(V0.7.2.6)類(lèi)庫(kù),同時(shí)基于.NET Core關(guān)于Configuration的設(shè)計(jì)風(fēng)格,做如下的框架設(shè)計(jì)
考慮到我會(huì)在該組件內(nèi)部創(chuàng)建ConsulClient實(shí)例,所以對(duì)ConsulClient構(gòu)造函數(shù)的一部分參數(shù)做了抽象提取,并添加到了IConsulConfigurationSource中,以增強(qiáng)該組件的靈活性。
之前說(shuō)過(guò),Consul中的配置信息是以JSON格式存儲(chǔ)的,所以此處使用到了Microsoft.Extensions.Configuration.Json.JsonConfigurationFileParser,用以將JSON格式的信息轉(zhuǎn)換為Configuration的通用格式Key/Value。
核心代碼 IConsulConfigurationSource
/// <summary>
/// ConsulConfigurationSource
/// </summary>
public interface IConsulConfigurationSource : IConfigurationSource
{
/// <summary>
/// CancellationToken
/// </summary>
CancellationToken CancellationToken { get; }
/// <summary>
/// Consul構(gòu)造函數(shù)實(shí)例,可自定義傳入
/// </summary>
Action<ConsulClientConfiguration> ConsulClientConfiguration { get; set; }
/// <summary>
/// Consul構(gòu)造函數(shù)實(shí)例,可自定義傳入
/// </summary>
Action<HttpClient> ConsulHttpClient { get; set; }
/// <summary>
/// Consul構(gòu)造函數(shù)實(shí)例,可自定義傳入
/// </summary>
Action<HttpClientHandler> ConsulHttpClientHandler { get; set; }
/// <summary>
/// 服務(wù)名稱(chēng)
/// </summary>
string ServiceKey { get; }
/// <summary>
/// 可選項(xiàng)
/// </summary>
bool Optional { get; set; }
/// <summary>
/// Consul查詢(xún)選項(xiàng)
/// </summary>
QueryOptions QueryOptions { get; set; }
/// <summary>
/// 重新加載延遲時(shí)間,單位是毫秒
/// </summary>
int ReloadDelay { get; set; }
/// <summary>
/// 是否在配置改變的時(shí)候重新加載
/// </summary>
bool ReloadOnChange { get; set; }
}
ConsulConfigurationSource
該類(lèi)提供了一個(gè)構(gòu)造函數(shù),用于接收ServiceKey和CancellationToken實(shí)例
public ConsulConfigurationSource(string serviceKey, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(serviceKey))
{
throw new ArgumentNullException(nameof(serviceKey));
}
this.ServiceKey = serviceKey;
this.CancellationToken = cancellationToken;
}
其build()方法也比較簡(jiǎn)單,主要是初始化ConsulConfigurationParser實(shí)例
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
ConsulConfigurationParser consulParser = new ConsulConfigurationParser(this);
return new ConsulConfigurationProvider(this, consulParser);
}
ConsulConfigurationParser
該類(lèi)比較復(fù)雜,主要實(shí)現(xiàn)Consul配置的獲取、監(jiān)控以及容錯(cuò)處理,公共方法源碼如下
/// <summary>
/// 獲取并轉(zhuǎn)換Consul配置信息
/// </summary>
/// <param name="reloading"></param>
/// <param name="source"></param>
/// <returns></returns>
public async Task<IDictionary<string, string>> GetConfig(bool reloading, IConsulConfigurationSource source)
{
try
{
QueryResult<KVPair> kvPair = await this.GetKvPairs(source.ServiceKey, source.QueryOptions, source.CancellationToken).ConfigureAwait(false);
if ((kvPair?.Response == null) && !source.Optional)
{
if (!reloading)
{
throw new FormatException(Resources.Error_InvalidService(source.ServiceKey));
}
return new Dictionary<string, string>();
}
if (kvPair?.Response == null)
{
throw new FormatException(Resources.Error_ValueNotExist(source.ServiceKey));
}
this.UpdateLastIndex(kvPair);
return JsonConfigurationFileParser.Parse(source.ServiceKey, new MemoryStream(kvPair.Response.Value));
}
catch (Exception exception)
{
throw exception;
}
}
/// <summary>
/// Consul配置信息監(jiān)控
/// </summary>
/// <param name="key"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public IChangeToken Watch(string key, CancellationToken cancellationToken)
{
Task.Run(() => this.RefreshForChanges(key, cancellationToken), cancellationToken);
return this.reloadToken;
}
另外,關(guān)于Consul的監(jiān)控主要利用了QueryResult.LastIndex屬性,該類(lèi)緩存了該屬性的值,并與實(shí)獲取的值進(jìn)行比較,以判斷是否需要重新加載內(nèi)存中的緩存配置
ConsulConfigurationProvider
該類(lèi)除了實(shí)現(xiàn)Load方法外,還會(huì)根據(jù)ReloadOnChange屬性,在構(gòu)造函數(shù)中注冊(cè)O(shè)nChange事件,用于重新加載配置信息,源碼如下:
public sealed class ConsulConfigurationProvider : ConfigurationProvider
{
private readonly ConsulConfigurationParser configurationParser;
private readonly IConsulConfigurationSource source;
public ConsulConfigurationProvider(IConsulConfigurationSource source, ConsulConfigurationParser configurationParser)
{
this.configurationParser = configurationParser;
this.source = source;
if (source.ReloadOnChange)
{
ChangeToken.OnChange(
() => this.configurationParser.Watch(this.source.ServiceKey, this.source.CancellationToken),
async () =>
{
await this.configurationParser.GetConfig(true, source).ConfigureAwait(false);
Thread.Sleep(source.ReloadDelay);
this.OnReload();
});
}
}
public override void Load()
{
try
{
this.Data = this.configurationParser.GetConfig(false, this.source).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (AggregateException aggregateException)
{
throw aggregateException.InnerException;
}
}
}
調(diào)用及運(yùn)行結(jié)果
此處調(diào)用在Program中實(shí)現(xiàn)
public class Program
{
public static void Main(string[] args)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
WebHost.CreateDefaultBuilder(args).ConfigureAppConfiguration(
(hostingContext, builder) =>
{
builder.AddConsul("userservice", cancellationTokenSource.Token, source =>
{
source.ConsulClientConfiguration = cco => cco.Address = new Uri("http://localhost:8500");
source.Optional = true;
source.ReloadOnChange = true;
source.ReloadDelay = 300;
source.QueryOptions = new QueryOptions
{
WaitIndex = 0
};
});
builder.AddConsul("commonservice", cancellationTokenSource.Token, source =>
{
source.ConsulClientConfiguration = cco => cco.Address = new Uri("http://localhost:8500");
source.Optional = true;
source.ReloadOnChange = true;
source.ReloadDelay = 300;
source.QueryOptions = new QueryOptions
{
WaitIndex = 0
};
});
}).UseStartup<Startup>().Build().Run();
}
}
以上就是本次介紹的全部知識(shí)點(diǎn)內(nèi)容,感謝大家對(duì)我們的支持。
上一篇:.net core EF Core調(diào)用存儲(chǔ)過(guò)程的方式
欄 目:ASP.NET
下一篇:ASP.NET Core靜態(tài)文件的使用方法
本文標(biāo)題:.NET Core 3.0之創(chuàng)建基于Consul的Configuration擴(kuò)展組件
本文地址:http://www.jygsgssxh.com/a1/ASP_NET/10926.html
您可能感興趣的文章
- 01-11如何給asp.net core寫(xiě)個(gè)簡(jiǎn)單的健康檢查
- 01-11淺析.Net Core中Json配置的自動(dòng)更新
- 01-11.net core高吞吐遠(yuǎn)程方法如何調(diào)用組件XRPC詳解
- 01-11.NET Core 遷移躺坑記續(xù)集之Win下莫名其妙的超時(shí)
- 01-11.NET開(kāi)發(fā)人員關(guān)于ML.NET的入門(mén)學(xué)習(xí)
- 01-11docker部署Asp.net core應(yīng)用的完整步驟
- 01-11.net core webapi jwt 更為清爽的認(rèn)證詳解
- 01-11ASP.NET Core靜態(tài)文件的使用方法
- 01-11.net core EF Core調(diào)用存儲(chǔ)過(guò)程的方式
- 01-11asp.net Core3.0區(qū)域與路由配置的方法


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-11vscode extension插件開(kāi)發(fā)詳解
- 01-11VsCode插件開(kāi)發(fā)之插件初步通信的方法
- 01-11如何給asp.net core寫(xiě)個(gè)簡(jiǎn)單的健康檢查
- 01-11.net core高吞吐遠(yuǎn)程方法如何調(diào)用組件
- 01-11淺析.Net Core中Json配置的自動(dòng)更新
- 01-11.NET開(kāi)發(fā)人員關(guān)于ML.NET的入門(mén)學(xué)習(xí)
- 01-11.NET Core 遷移躺坑記續(xù)集之Win下莫名其
- 01-11.net core webapi jwt 更為清爽的認(rèn)證詳解
- 01-11docker部署Asp.net core應(yīng)用的完整步驟
- 01-11ASP.NET Core靜態(tài)文件的使用方法
隨機(jī)閱讀
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法


