创建CustomConfigurationProvider
首先,我们需要创建一个自定义的 ConfigurationSource 和 ConfigurationProvider 来支持配置文件的读取和监控。
public class CustomConfigurationSource : IConfigurationSource
{
public string FilePath { get; }
public CustomConfigurationSource(string filePath)
{
FilePath = filePath;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new CustomConfigurationProvider(this);
}
}
public class CustomConfigurationProvider : ConfigurationProvider, IDisposable
{
private readonly string _filePath;
private FileSystemWatcher _fileWatcher;
public CustomConfigurationProvider(CustomConfigurationSource source)
{
_filePath = source.FilePath;
Load();
_fileWatcher = new FileSystemWatcher(Path.GetDirectoryName(_filePath))
{
Filter = Path.GetFileName(_filePath),
NotifyFilter = NotifyFilters.LastWrite
};
_fileWatcher.Changed += OnChanged;
_fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
Load();
OnReload(); // 通知配置系统已更新
}
public override void Load()
{
// 加载配置数据
Data = JsonConfigurationFileParser.Parse(File.ReadAllText(_filePath));
}
public void Dispose()
{
_fileWatcher?.Dispose();
}
}
public class CustomConfigurationProvider : ConfigurationProvider
{
private readonly string _filePath;
public CustomConfigurationProvider(string filePath)
{
_filePath = filePath;
}
public override void Load()
{
// Load configuration data from the file
Data = LoadConfigurationFromFile(_filePath);
}
private IDictionary<string, string> LoadConfigurationFromFile(string filePath)
{
// Implement logic to load data from the file
var data = new Dictionary<string, string>();
// Example: data["Key"] = "Value";
return data;
}
}
创建 Background Service
public class ConfigurationUpdateService : BackgroundService
{
private readonly IConfigurationRoot _configurationRoot;
private readonly TimeSpan _updateInterval = TimeSpan.FromMinutes(5);
public ConfigurationUpdateService(IConfigurationRoot configurationRoot)
{
_configurationRoot = configurationRoot;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Check for updates and reload the configuration if needed
ReloadConfigurationIfChanged();
// Wait for the next check
await Task.Delay(_updateInterval, stoppingToken);
}
}
private void ReloadConfigurationIfChanged()
{
// Assuming the custom provider is used
var customProvider = _configurationRoot.Providers
.OfType<CustomConfigurationProvider>()
.FirstOrDefault();
if (customProvider != null)
{
customProvider.Load();
customProvider.OnReload();
}
}
}
注册服务和配置 在program.cs里面
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Register the custom configuration source
builder.Configuration.Add(new CustomConfigurationSource("path/to/config.json"));
// Register the background service
builder.Services.AddHostedService<ConfigurationUpdateService>();
var app = builder.Build();
app.Run();
}
}
配置重新加载:当后台服务检测到更改时,它会在提供程序上调用 Load() 以刷新数据,然后触发 OnReload() 以通知配置系统。
使用IOptionsMonitor
public class MyOptions
{
public string Setting1 { get; set; }
public int Setting2 { get; set; }
}
{
"MyOptions": {
"Setting1": "Value1",
"Setting2": 42
}
}
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Register options and bind them to configuration section
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
app.Run();
}
}
public class MyService
{
private readonly IOptionsMonitor<MyOptions> _optionsMonitor;
public MyService(IOptionsMonitor<MyOptions> optionsMonitor)
{
_optionsMonitor = optionsMonitor;
// Subscribe to changes
_optionsMonitor.OnChange(OnOptionsChanged);
// Access the current value
var currentOptions = _optionsMonitor.CurrentValue;
Console.WriteLine($"Initial Setting1: {currentOptions.Setting1}");
Console.WriteLine($"Initial Setting2: {currentOptions.Setting2}");
}
private void OnOptionsChanged(MyOptions options)
{
// This method is called whenever the options change
Console.WriteLine($"Updated Setting1: {options.Setting1}");
Console.WriteLine($"Updated Setting2: {options.Setting2}");
}
}
- IOptions
用途: 提供一种简单的方式来访问应用程序的配置选项,适合那些配置在应用程序生命周期内不会改变的场景。
特点:
IOptions
配置选项在应用启动时加载,并在应用运行期间保持不变。
示例:
Copy code
public class MyService
{
private readonly MyOptions _options;
public MyService(IOptions<MyOptions> options)
{
_options = options.Value;
Console.WriteLine($"Setting1: {_options.Setting1}");
Console.WriteLine($"Setting2: {_options.Setting2}");
}
}
- IOptionsSnapshot
用途: 提供一次性(per-request)的配置选项快照,通常用于需要在每个请求中读取当前配置状态的场景。
特点:
适用于基于依赖注入的作用域,例如在 ASP.NET Core 中每个 HTTP 请求期间的配置。
在每个请求的生命周期内,可以获取配置的最新值。
示例:
public class MyService
{
private readonly MyOptions _options;
public MyService(IOptionsSnapshot<MyOptions> options)
{
_options = options.Value;
Console.WriteLine($"Setting1: {_options.Setting1}");
Console.WriteLine($"Setting2: {_options.Setting2}");
}
}
使用 IOptionsSnapshot
3. IOptionsFactory
用途: 负责创建 T 类型的选项实例。通常不直接使用,而是由框架在内部使用来创建选项实例。
特点:
可以通过自定义 IOptionsFactory
示例:
大多数情况下,不需要直接使用或实现 IOptionsFactory
4. IOptionsValidator
用途: 用于验证配置选项是否符合某些规则或要求。可以在选项加载后自动验证其有效性。
特点:
允许你在选项初始化时进行验证,并抛出异常或生成错误消息。
示例:
可以自定义实现 IOptionsValidator
5. IOptionsChangeTokenSource
用途: 提供一个 IChangeToken,用于检测配置变化。
特点:
与 IOptionsMonitor
示例:
通常在自定义配置源中使用,以便在配置数据发生变化时,触发 IOptionsMonitor
6. IOptionsMonitorCache
用途: 管理 IOptionsMonitor
特点:
提供一种方法来清除缓存并强制重新加载选项。
示例:
在某些场景下,你可能需要手动清除缓存,以便获取最新的配置数据。
什么时候选择使用哪个类型?
IOptions
IOptionsSnapshot
IOptionsMonitor
IOptionsFactory
这些选项机制使得 .NET Core 的配置系统非常灵活,可以满足从简单到复杂的配置需求。