實現自定義配置源至少需要添加如下成員: 實現IConfigurationSource介面的配置源; 實現IConfigurationProvider介面或虛基類ConfigurationProvider的配置提供程式; 添加配置源的IConfigurationBuilder擴展方法; 如自定義一個T ...
實現自定義配置源至少需要添加如下成員:
- 實現IConfigurationSource介面的配置源;
- 實現IConfigurationProvider介面或虛基類ConfigurationProvider的配置提供程式;
- 添加配置源的IConfigurationBuilder擴展方法;
如自定義一個TXT文本文件配置源:
添加配置源
配置源負責創建配置提供程式,以及監聽文件修改。監聽文件修改可以使用FileSystemWatcher,通過監聽Changed事件監聽配置文件的修改。使用ConfigurationReloadToken作為IChangeToken,當監聽到文件修改時調用取消令牌的取消操作,進而通知訂閱者文件已更改。
public class TxtConfigurationSource : IConfigurationSource, IDisposable
{
private FileSystemWatcher? _fileWatcher;
private ConfigurationReloadToken _reloadToken;
public TxtConfigurationSource(string path, bool reloadOnChange = true)
{
FilePath = path;
ReloadOnChange = reloadOnChange;
_fileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory());
_fileWatcher.Filter = "*.txt";
_fileWatcher.EnableRaisingEvents = true;
_fileWatcher.Changed += _fileWatcher_Changed;
_reloadToken = new ConfigurationReloadToken();
}
private void _fileWatcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.FullPath != FilePath)
return;
if (_reloadToken.HasChanged)
return;
// 觸發事件
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken,
new ConfigurationReloadToken());
previousToken.OnReload();
}
public bool ReloadOnChange { get; set; }
public string FilePath { get; set; }
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new TxtConfigurationProvider(this);
}
public IChangeToken GetChangeToken() => _reloadToken;
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
_fileWatcher?.Dispose();
}
}
添加配置提供程式
配置提供程式負責載入配置文件,並訂閱配置源中的配置修改事件。通過ChangeToken.OnChange()方法進行事件訂閱,當監聽到文件改變時,重新載入文件:
public class TxtConfigurationProvider : ConfigurationProvider, IDisposable
{
private readonly IDisposable _changeTokenRegistration;
public TxtConfigurationProvider(TxtConfigurationSource source)
:base()
{
Source = source ?? throw new ArgumentNullException(nameof(source));
if (Source.ReloadOnChange)
{
_changeTokenRegistration = ChangeToken.OnChange(
() => Source.GetChangeToken(),
() =>
{
Thread.Sleep(300);
Load();
});
}
}
public TxtConfigurationSource Source { get; }
public override void Load()
{
if (!File.Exists(Source.FilePath))
return;
else
{
Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var lines = File.ReadAllLines(Source.FilePath);
foreach (var line in lines)
{
var array = line.Replace(":", ":").Split(':');
if (array.Length < 2)
continue;
Data.Add(line.Substring(0, line.LastIndexOf(':')), array.Last());
}
}
OnReload();
}
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
_changeTokenRegistration?.Dispose();
}
}
添加配置源擴展方法
添加IConfigurationBuilder擴展方法,方便將自定義配置源添加到IConfigurationBuilder中:
public static IConfigurationBuilder AddTxtFile(this IConfigurationBuilder builder,
string path, bool reloadOnChange)
{
if (builder == null)
throw new ArgumentNullException(nameof(builder));
if (string.IsNullOrEmpty(path))
throw new ArgumentException($"文件不能為空:{nameof(path)}");
return builder.Add(new TxtConfigurationSource(path, reloadOnChange));
}
使用
首先通過擴展方法添加配置源,調用IConfigurationBuilder.Build()方法後即可通過IConfiguration獲取配置項。通過ChangeToken.OnChange()方法訂閱配置修改事件。
using ConfigurationTest;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddTxtFile(Path.Combine(Directory.GetCurrentDirectory(), "config.txt"), reloadOnChange: true);
// 通過IConfiguration直接讀取指定配置
IConfiguration configuration = configurationBuilder.Build();
Console.WriteLine($"FileProvider:Source:{configuration.GetSection("FileProvider:Source").Value}");
Console.WriteLine($"Provider:{configuration["FileProvider:Provider"]}");
Console.WriteLine();
// 通過綁定選項獲取配置
FileProviderOptions fileProviderOptions = new FileProviderOptions();
configuration.GetSection("FileProvider").Bind(fileProviderOptions);
Console.WriteLine($"FileProvider.Source = {fileProviderOptions.Source}");
Console.WriteLine($"FileProvider.Provider = {fileProviderOptions.Provider}");
Console.WriteLine();
// 監聽配置修改
var disable = ChangeToken.OnChange(() => configuration.GetReloadToken(),
() =>
{
foreach (var section in configuration.GetChildren())
{
PrintAllConfig(section);
}
Console.WriteLine();
Console.WriteLine("按“q”退出");
});
Console.WriteLine("按“q”退出");
while (Console.ReadLine() != "q")
{
}
disable.Dispose();
void PrintAllConfig(IConfigurationSection config)
{
var sections = config.GetChildren();
if(sections == null || sections.Count() == 0)
Console.WriteLine($"{config.Key} : {config.Value}");
else
{
foreach (var section in sections)
{
PrintAllConfig(section);
}
}
}
class FileProviderOptions
{
public string Source { get; set; }
public string Provider { get; set; }
}
// config.txt
FileProvider:Source:TxtSource
FileProvider:Provider:TxtProvider
轉載請註明出處,歡迎交流。