Configuration

ConfigurationRoot

public interface IConfiguration
{
string? this[string key] { get; }
IChangeToken GetReloadToken();
}

public interface IConfigurationRoot : IConfiguration
{
void Reload();
}

public class ConfigurationRoot : IConfigurationRoot
{
private readonly List _providers;
private readonly IList _changeTokenRegistrations;
private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();

public ConfigurationRoot(List providers)
{
this._providers = providers;
this._changeTokenRegistrations = new List(providers.Count);
foreach (IConfigurationProvider p in providers)
{
p.Load();
_changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
}
}

public string? this[string key]
{
get
{
return GetConfiguration(_providers, key);
}
}

internal static string? GetConfiguration(List providers, string key)
{
for (var i = providers.Count - 1; i >= 0; i--)
{
var provider = providers[i];
if (provider.TryGet(key, out var value))
{
return value;
}
}

return null;
}

public IChangeToken GetReloadToken()
{
return _changeToken;
}

public void Reload()
{
foreach (IConfigurationProvider provider in _providers)
{
provider.Load();
}
RaiseChanged();
}

private void RaiseChanged()
{
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
previousToken.OnReload();
}

}

ConfigurationReloadToken

public class ConfigurationReloadToken : IChangeToken
{
private CancellationTokenSource _cts = new CancellationTokenSource();

public bool HasChanged => _cts.IsCancellationRequested;

public bool ActiveChangeCallbacks => true;

public IDisposable RegisterChangeCallback(Action<object?> callback, object? state) => _cts.Token.Register(callback, state);

public void OnReload() => _cts.Cancel();
}

ConfigurationSource

public interface IConfigurationSource
{
IConfigurationProvider Build(IConfigurationBuilder builder);
}

ConfigurationProvider

public interface IConfigurationProvider
{
bool TryGet(string key, out string? value);

void Load();

IChangeToken GetReloadToken();
}

public abstract class ConfigurationProvider : IConfigurationProvider
{
private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();

protected ConfigurationProvider()
{
Data = new Dictionary<string, string?>(StringComparer.InvariantCultureIgnoreCase);
}

protected Dictionary<string, string?> Data { get; set; }

public virtual bool TryGet(string key, out string? value)
{
return Data.TryGetValue(key, out value);
}

public virtual void Load()
{

}

public IChangeToken GetReloadToken()
{
return _reloadToken;
}

protected void OnReload()
{
ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
previousToken.OnReload();
}
}

ConfigurationBuilder

public interface IConfigurationBuilder
{
IConfigurationRoot Build();
}

public class ConfigurationBuilder : IConfigurationBuilder
{
public IList Sources { get; } = new List();

public IConfigurationBuilder Add(IConfigurationSource source)
{
Sources.Add(source);
return this;
}

public IConfigurationRoot Build()
{
var providers = new List();

foreach (var source in Sources)
{
providers.Add(source.Build(this));
}

return new ConfigurationRoot(providers);
}
}

示例

public class DemoConfigurationSource : IConfigurationSource
{
public string Path;

public DemoConfigurationSource(string path)
{
Path = path;
}

public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new DemoConfigurationProvider(this);
}

public Dictionary<string, string> LoadData()
{
return File.ReadAllLines(Path)
.Where(x => !string.IsNullOrWhiteSpace(x) && x.Contains("😊)
.ToDictionary(x => x.Split("😊[0], x => x.Split("😊[1]);
}
}

public class DemoConfigurationProvider : ConfigurationProvider
{
private DemoConfigurationSource _source { get; }

public DemoConfigurationProvider(DemoConfigurationSource source)
{
_source = source;

var dir = Path.GetDirectoryName(source.Path);
var fileName = Path.GetFileName(source.Path);
var provider = new PhysicalFileProvider(dir);

ChangeToken.OnChange(
() => provider.Watch(fileName),
() =>
{
Thread.Sleep(5000);
Load();
// 通知外部有变动
OnReload();
});
}

public override void Load()
{
Data = _source.LoadData();
}

private Dictionary<string, string> LoadData()
{
return File.ReadAllLines(_source.Path)
.Where(x => !string.IsNullOrWhiteSpace(x) && x.Contains("😊)
.ToDictionary(x => x.Split("😊[0], x => x.Split("😊[1]);
}
}

public static class DemoConfigurationExtensions
{
public static IConfigurationBuilder AddDemo(this ConfigurationBuilder builder, string path)
{
builder.Add(new DemoConfigurationSource(path));
return builder;
}
}

static void Main(string[] args)
{
//var serviceCollection = new ServiceCollection();

//var service = serviceCollection.BuildServiceProvider();

var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddDemo("d://1.txt");

var configuration = configurationBuilder.Build();

ChangeToken.OnChange(() => configuration.GetReloadToken(), () =>
{
var value = configuration["a1"];
Console.WriteLine($"a1 = {value}");
});

//// 手动触发加载
//configuration.Reload();

Console.ReadLine();
}

posted @ 2024-09-11 17:56  pojianbing  阅读(68)  评论(0)    收藏  举报