自定义Configuration配置源

  • 自定义Configuration配置源已关闭评论
  • 59 次浏览
  • A+
所属分类:.NET技术
摘要

实现自定义配置源至少需要添加如下成员:如自定义一个TXT文本文件配置源:

实现自定义配置源至少需要添加如下成员:

  • 实现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