翼度科技»论坛 编程开发 .net 查看内容

自定义Configuration配置源

2

主题

2

帖子

6

积分

新手上路

Rank: 1

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

  • 实现IConfigurationSource接口的配置源;
  • 实现IConfigurationProvider接口或虚基类ConfigurationProvider的配置提供程序;
  • 添加配置源的IConfigurationBuilder扩展方法;
如自定义一个TXT文本文件配置源:
添加配置源

配置源负责创建配置提供程序,以及监听文件修改。监听文件修改可以使用FileSystemWatcher,通过监听Changed事件监听配置文件的修改。使用ConfigurationReloadToken作为IChangeToken,当监听到文件修改时调用取消令牌的取消操作,进而通知订阅者文件已更改。
  1. public class TxtConfigurationSource : IConfigurationSource, IDisposable
  2. {
  3.     private FileSystemWatcher? _fileWatcher;
  4.     private ConfigurationReloadToken _reloadToken;
  5.     public TxtConfigurationSource(string path, bool reloadOnChange = true)
  6.     {
  7.         FilePath = path;
  8.         ReloadOnChange = reloadOnChange;
  9.         _fileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory());
  10.         _fileWatcher.Filter = "*.txt";
  11.         _fileWatcher.EnableRaisingEvents = true;
  12.         _fileWatcher.Changed += _fileWatcher_Changed;
  13.         _reloadToken = new ConfigurationReloadToken();
  14.     }
  15.     private void _fileWatcher_Changed(object sender, FileSystemEventArgs e)
  16.     {
  17.         if (e.FullPath != FilePath)
  18.             return;
  19.         
  20.         if (_reloadToken.HasChanged)
  21.             return;
  22.         // 触发事件
  23.         ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken,
  24.             new ConfigurationReloadToken());
  25.         previousToken.OnReload();
  26.     }
  27.     public bool ReloadOnChange { get; set; }
  28.     public string FilePath { get; set; }
  29.     public IConfigurationProvider Build(IConfigurationBuilder builder)
  30.     {
  31.         return new TxtConfigurationProvider(this);
  32.     }
  33.     public IChangeToken GetChangeToken() => _reloadToken;
  34.     public void Dispose() => Dispose(true);
  35.     protected virtual void Dispose(bool disposing)
  36.     {
  37.         _fileWatcher?.Dispose();
  38.     }
  39. }
复制代码
添加配置提供程序

配置提供程序负责加载配置文件,并订阅配置源中的配置修改事件。通过ChangeToken.OnChange()方法进行事件订阅,当监听到文件改变时,重新加载文件:
  1. public class TxtConfigurationProvider : ConfigurationProvider, IDisposable
  2. {
  3.     private readonly IDisposable _changeTokenRegistration;
  4.     public TxtConfigurationProvider(TxtConfigurationSource source)
  5.         :base()
  6.     {
  7.         Source = source ?? throw new ArgumentNullException(nameof(source));
  8.         if (Source.ReloadOnChange)
  9.         {
  10.             _changeTokenRegistration = ChangeToken.OnChange(
  11.                 () => Source.GetChangeToken(),
  12.                 () =>
  13.                 {
  14.                     Thread.Sleep(300);
  15.                     Load();
  16.                 });
  17.         }
  18.     }
  19.     public TxtConfigurationSource Source { get; }
  20.     public override void Load()
  21.     {
  22.         if (!File.Exists(Source.FilePath))
  23.             return;
  24.         else
  25.         {
  26.             Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  27.             var lines = File.ReadAllLines(Source.FilePath);
  28.             foreach (var line in lines)
  29.             {
  30.                 var array = line.Replace(":", ":").Split(':');
  31.                 if (array.Length < 2)
  32.                     continue;
  33.                 Data.Add(line.Substring(0, line.LastIndexOf(':')), array.Last());
  34.             }
  35.         }
  36.         OnReload();
  37.     }
  38.     public void Dispose() => Dispose(true);
  39.     protected virtual void Dispose(bool disposing)
  40.     {
  41.         _changeTokenRegistration?.Dispose();
  42.     }
  43. }
复制代码
添加配置源扩展方法

添加IConfigurationBuilder扩展方法,方便将自定义配置源添加到IConfigurationBuilder中:
  1. public static IConfigurationBuilder AddTxtFile(this IConfigurationBuilder builder,
  2.     string path, bool reloadOnChange)
  3. {
  4.     if (builder == null)
  5.         throw new ArgumentNullException(nameof(builder));
  6.     if (string.IsNullOrEmpty(path))
  7.         throw new ArgumentException($"文件不能为空:{nameof(path)}");
  8.     return builder.Add(new TxtConfigurationSource(path, reloadOnChange));
  9. }
复制代码
使用

首先通过扩展方法添加配置源,调用IConfigurationBuilder.Build()方法后即可通过IConfiguration获取配置项。通过ChangeToken.OnChange()方法订阅配置修改事件。
  1. using ConfigurationTest;
  2. using Microsoft.Extensions.Configuration;
  3. using Microsoft.Extensions.Primitives;
  4. IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
  5.     .AddTxtFile(Path.Combine(Directory.GetCurrentDirectory(), "config.txt"), reloadOnChange: true);
  6. // 通过IConfiguration直接读取指定配置
  7. IConfiguration configuration = configurationBuilder.Build();
  8. Console.WriteLine($"FileProvider:Source:{configuration.GetSection("FileProvider:Source").Value}");
  9. Console.WriteLine($"Provider:{configuration["FileProvider:Provider"]}");
  10. Console.WriteLine();
  11. // 通过绑定选项获取配置
  12. FileProviderOptions fileProviderOptions = new FileProviderOptions();
  13. configuration.GetSection("FileProvider").Bind(fileProviderOptions);
  14. Console.WriteLine($"FileProvider.Source = {fileProviderOptions.Source}");
  15. Console.WriteLine($"FileProvider.Provider = {fileProviderOptions.Provider}");
  16. Console.WriteLine();
  17. // 监听配置修改
  18. var disable = ChangeToken.OnChange(() => configuration.GetReloadToken(),
  19.                                    () =>
  20.                                    {
  21.                                        foreach (var section in configuration.GetChildren())
  22.                                        {
  23.                                            PrintAllConfig(section);
  24.                                        }
  25.                                        
  26.                                        Console.WriteLine();
  27.                                        Console.WriteLine("按“q”退出");
  28.                                    });
  29. Console.WriteLine("按“q”退出");
  30. while (Console.ReadLine() != "q")
  31. {
  32. }
  33. disable.Dispose();
  34. void PrintAllConfig(IConfigurationSection config)
  35. {
  36.     var sections = config.GetChildren();
  37.     if(sections == null || sections.Count() == 0)
  38.         Console.WriteLine($"{config.Key} : {config.Value}");
  39.     else
  40.     {
  41.         foreach (var section in sections)
  42.         {
  43.             PrintAllConfig(section);
  44.         }
  45.     }
  46. }
  47. class FileProviderOptions
  48. {
  49.     public string Source { get; set; }
  50.     public string Provider { get; set; }
  51. }
复制代码
  1. // config.txt
  2. FileProvider:Source:TxtSource
  3. FileProvider:Provider:TxtProvider
复制代码
来源:https://www.cnblogs.com/louzixl/archive/2023/12/02/17871159.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具