一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - ASP.NET教程 - .Net Core配置Configuration具體實(shí)現(xiàn)

.Net Core配置Configuration具體實(shí)現(xiàn)

2021-12-18 17:29張三~~ ASP.NET教程

這篇文章主要介紹了.Net Core配置Configuration具體實(shí)現(xiàn),文中運(yùn)用大量代碼進(jìn)行講解,如果有對(duì)相關(guān)知識(shí)感興趣的小伙伴可以參考這篇文章,希望可以幫助到你

最近又研究了一下.NetCore配置選項(xiàng)的源碼實(shí)現(xiàn),又學(xué)習(xí)到了不少東西。這篇文章先寫(xiě)一下IConfiguration的學(xué)習(xí)成果,Options的后面補(bǔ)上

核心類

  • ConfigurationBuilder:IConfigurationBuilder  (構(gòu)建IConfiguration)
  • IConfigurationSource (配置數(shù)據(jù)來(lái)源)
  • IConfigurationProvider (將配置源的原始結(jié)構(gòu)轉(zhuǎn)為為IDictionary<string, string>)
  • ConfigurationRoot:IConfigurationRoot:IConfiguration  (配置根節(jié)點(diǎn))

構(gòu)建

ConfigurationBuilder

下面是ConfigurationBuilder中的主要代碼

可以看到ConfigurationBuilder的主要功能就是配置數(shù)據(jù)源到集合中

在Build時(shí)依次調(diào)用IConfigurationSource的Build函數(shù),并將返回的IConfigurationProvider加入到List中

最后用IConfigurationProvider的集合構(gòu)建一個(gè)ConfigurationRoot對(duì)象

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public IList<IConfigurationSource> Sources = new List<IConfigurationSource>();
 
public IConfigurationBuilder Add(IConfigurationSource source)
{
    Sources.Add(source);
    return this;
}
 
public IConfigurationRoot Build()
{
    List<IConfigurationProvider> list = new List<IConfigurationProvider>();
    foreach (IConfigurationSource source in Sources)
    {
        IConfigurationProvider item = source.Build(this);
        list.Add(item);
    }
 
    return new ConfigurationRoot(list);
}

IConfigurationSource

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class EnvironmentVariablesConfigurationSource : IConfigurationSource
{
    public string Prefix;
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EnvironmentVariablesConfigurationProvider(Prefix);
    }
    public EnvironmentVariablesConfigurationSource()
    {
    }
}
    
   
public class CommandLineConfigurationSource : IConfigurationSource
{
    public IDictionary<string, string> SwitchMappings;
    public IEnumerable<string> Args;
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new CommandLineConfigurationProvider(Args, SwitchMappings);
    }
    public CommandLineConfigurationSource()
    {
    }
}
 
//JsonConfigurationSource繼承自FileConfigurationSource,我這里將其合為一個(gè)了
public abstract class JsonConfigurationSource : IConfigurationSource
{
 public IFileProvider FileProvider { get; set; }
 public string Path { get; set; }
 public bool Optional { get; set; }
 public bool ReloadOnChange { get; set; }
 public int ReloadDelay { get; set; } = 250;
 
 public Action<FileLoadExceptionContext> OnLoadException { get; set; }
    
 public IConfigurationProvider Build(IConfigurationBuilder builder)
 {
  FileProvider = FileProvider ?? builder.GetFileProvider();
  OnLoadException = OnLoadException ?? builder.GetFileLoadExceptionHandler();
  return new JsonConfigurationProvider(this);
 }
    
 public void ResolveFileProvider()
 {
  if (FileProvider == null && !string.IsNullOrEmpty(Path) && System.IO.Path.IsPathRooted(Path))
  {
   string directoryName = System.IO.Path.GetDirectoryName(Path);
   string text = System.IO.Path.GetFileName(Path);
   while (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
   {
    text = System.IO.Path.Combine(System.IO.Path.GetFileName(directoryName), text);
    directoryName = System.IO.Path.GetDirectoryName(directoryName);
   }
   if (Directory.Exists(directoryName))
   {
    FileProvider = new PhysicalFileProvider(directoryName);
    Path = text;
   }
  }
 }
}

上面展示了比較常用的三種ConfigurationSource,代碼都比較簡(jiǎn)單。

也很容易看出來(lái)ConfigurationSource的作用就是配置數(shù)據(jù)源,并不解析數(shù)據(jù)。

解析數(shù)據(jù)源的功能由 IConfigurationProvider完成

ConfigurationProvider

下面為IConfigurationProvider接口定義的5個(gè)函數(shù)

?
1
2
3
4
5
6
7
8
9
10
11
12
public interface IConfigurationProvider
{
 bool TryGet(string key, out string value);
 
 void Set(string key, string value);
 
 IChangeToken GetReloadToken();
 
 void Load();
 
 IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
}

ConfigurationProvider是一個(gè)抽象類,繼承了IConfigurationProvider接口

在新建Provider時(shí)一般都會(huì)選擇直接繼承ConfigurationProvider,接下來(lái)看一下ConfigurationProvider的幾個(gè)核心方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class ConfigurationProvider : IConfigurationProvider
{
 private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
    
 protected IDictionary<string, string> Data= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
 public virtual bool TryGet(string key, out string value)=>Data.TryGetValue(key, out value);
 
 public virtual void Set(string key, string value)=>Data[key] = value;
 
 public virtual void Load(){}
 
 public IChangeToken GetReloadToken()
 {
  return _reloadToken;
 }
 
 protected void OnReload()
 {
 ConfigurationReloadToken configurationReloadToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
  configurationReloadToken.OnReload();
 }

可以推測(cè)出:

  • Load函數(shù)負(fù)責(zé)從源數(shù)據(jù)讀取數(shù)據(jù)然后給字典Data賦值
  • ConfigurationProvider將數(shù)據(jù)存儲(chǔ)在字典Data中,增加修改都是對(duì)字典的操作
  • 每個(gè)ConfigurationProvider都會(huì)生成一個(gè)IChangeToken,在OnReload函數(shù)被調(diào)用時(shí)生成新的Token,并調(diào)用原Token的OnReload函數(shù)

ConfigurationRoot

在ConfigurationBuilder的Build函數(shù)中,我們生成了一個(gè)ConfigurationRoot,并給他傳遞了所有的ConfigrationProvider列表,下面我們看看他用我們的Provider都做了啥吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();
 
public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
    _providers = providers;
    _changeTokenRegistrations = new List<IDisposable>(providers.Count);
    foreach (IConfigurationProvider p in providers)
    {
        p.Load();
        ChangeToken.OnChange(p.GetReloadToken,
           delegate{
     var oldToken=Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
                 oldToken.OnReload();
                })
    }
}
 
public IChangeToken GetReloadToken()=>_changeToken;

上面的代碼也對(duì)部分地方進(jìn)行了簡(jiǎn)化。可以看到ConfigurationRoot在生成時(shí)主要就做了兩件事

  • 1.調(diào)用Provider的Load函數(shù),這會(huì)給Provider的Data賦值
  • 2.讀取Provider的ReloadToken,每個(gè)Provider的Reload事件都會(huì)觸發(fā)ConfigurationRoot自己的ReloadToken的Reload事件

至此配置的數(shù)據(jù)源構(gòu)建這塊就分析完啦!

查詢

常規(guī)的配置查詢有兩種基本方式 :索引器和GetSection(string key)

其余的GetValue等等都是一些擴(kuò)展方法,本篇文章不對(duì)此進(jìn)行展開(kāi)研究

索引器

索引器的查詢執(zhí)行的方式是倒敘查詢所有的Provider,然后調(diào)用Provider的TryGet函數(shù),在查詢時(shí)重名的Key,最后加入的會(huì)生效。

賦值則是依次調(diào)用每個(gè)Provider的Set函數(shù)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public string this[string key]
{
 get
 {
  for (int num = _providers.Count - 1; num >= 0; num--)
  {
   if (_providers[num].TryGet(key, out var value))
   {
    return value;
   }
  }
  return null;
 }
 set
 {
  foreach (IConfigurationProvider provider in _providers)
  {
   provider.Set(key, value);
  }
 }
}

GetSection

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public IConfigurationSection GetSection(string key)
{
 return new ConfigurationSection(this, key);
}
 
public class ConfigurationSection : IConfigurationSection, IConfiguration
{
 private readonly IConfigurationRoot _root;
 private readonly string _path;
 private string _key;
 public string Value
 {
  get
  {
   return _root[Path];
  }
  set
  {
   _root[Path] = value;
  }
 }
 
    //ConfigurationPath.Combine = string.Join(":",paramList);
 public string this[string key]
 {
  get
  {
   return _root[ConfigurationPath.Combine(Path, key)];
  }
  set
  {
   _root[ConfigurationPath.Combine(Path, key)] = value;
  }
 }
 
 public ConfigurationSection(IConfigurationRoot root, string path)
 {
  _root = root;
  _path = path;
 }
 
 public IConfigurationSection GetSection(string key)
 {
  return _root.GetSection(ConfigurationPath.Combine(Path, key));
 }
 
 public IEnumerable<IConfigurationSection> GetChildren()
 {
  return _root.GetChildrenImplementation(Path);
 }
 
 public IChangeToken GetReloadToken()
 {
  return _root.GetReloadToken();
 }
}

可以看到GetSection會(huì)生成一個(gè)ConfigurationSection對(duì)象

而ConfigurationSection在讀取/設(shè)置值時(shí)實(shí)際上就是對(duì)查詢的Key用:拼接,然后調(diào)用IConfigurationRoot(_root)的賦值或查詢函數(shù)

關(guān)于Configuration的配置和讀取的知識(shí)點(diǎn)大概就是以上這些了,還有更深入的涉及到對(duì)象的綁定這一塊Get<> Bind<> GetChildren()等,比較難讀,要一行一行代碼看,以后有時(shí)間可能再研究一下

最后貼上一個(gè)從數(shù)據(jù)加載配置源并動(dòng)態(tài)更新的小例子

DBConfiguration示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
public void Run()
 {
     var builder = new ConfigurationBuilder();
     var dataProvider = new DBDataProvider();
     builder.Sources.Add(new DBConfigurationSource() { DataProvider = dataProvider, ReloadOnChange = true, Table = "config" });
     IConfigurationRoot config = builder.Build();
 
     Console.WriteLine(config["time"]);
     Task.Run(() =>
              {
                  while (true)
                  {
                      Thread.Sleep(2000);
                      dataProvider.Update("config");
                      Console.WriteLine($"讀取配置時(shí)間:{config["time"]}");
                  }
              });
     Thread.Sleep(20000);
 }
public class DBConfigurationProvider : ConfigurationProvider
{
    private DBConfigurationSource Source { get; }
    public DBConfigurationProvider(DBConfigurationSource source)
    {
        Source = source;
    }
 
    public override void Load()
    {
        if (Source.ReloadOnChange)
        {
            ChangeToken.OnChange(() => Source.DataProvider.Watch(Source.Table), LoadData);
        }
        LoadData();
    }
 
    private void LoadData()
    {
        var data = Source.DataProvider.GetData(Source.Table);
        Load(data);
        OnReload();
    }
 
    public void Load(Dictionary<string, object> data)
    {
        var dic = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        foreach (var element in data)
        {
            dic.Add(element.Key, element.Value?.ToString());
        }
        base.Data = dic;
    }
}
 
public class DBConfigurationSource : IConfigurationSource
{
    public DBDataProvider DataProvider { get; set; }
    public string Table { get; set; }
    public bool ReloadOnChange { get; set; }
    public bool Optional { get; set; }
 
    public DBConfigurationSource()
    {
    }
 
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new DBConfigurationProvider(this);
    }
}
 
public class DBDataProvider
{
    private ConcurrentDictionary<string, CancellationTokenSource> tableToken = new ConcurrentDictionary<string, CancellationTokenSource>();
    public DBDataProvider()
    {
    }
 
    public Dictionary<string, object> GetData(string table)
    {
        switch (table)
        {
            case "config":
                return GetConfig();
        }
        return new Dictionary<string, object>();
    }
 
    public void Update(string table)
    {
        Console.WriteLine($"更新數(shù)據(jù)庫(kù)數(shù)據(jù)table:{table}");
        if (tableToken.TryGetValue(table, out CancellationTokenSource cts))
        {
            var oldCts = cts;
            tableToken[table] = new CancellationTokenSource();
            oldCts.Cancel();
        }
    }
 
    private Dictionary<string, object> GetConfig()
    {
        var valueDic = new Dictionary<string, object>();
        valueDic.TryAdd("time", DateTime.Now.ToString());
        valueDic.TryAdd("weather", "windy");
        valueDic.TryAdd("people_number:male", 100);
        valueDic.TryAdd("people_number:female", 150);
        return valueDic;
    }
 
    public IChangeToken Watch(string table)
    {
        var cts = tableToken.GetOrAdd(table, x => new CancellationTokenSource());
        return new CancellationChangeToken(cts.Token);
    }
}

到此這篇關(guān)于.Net Core配置Configuration具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān).Net Core Configuration內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://www.cnblogs.com/bluesummer/p/15236098.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 不卡一区二区三区 | 五月婷婷在线观看 | 亚州第一页 | 日本免费精品 | 婚色阿花在线全文免费笔 | 高清视频一区二区三区 | 91在线 在线播放 | jk制服白丝超短裙流白浆 | 美女免费观看一区二区三区 | 边摸边吃奶玩乳尖视频 | 成人国产在线视频在线观看 | 亚洲va天堂va国产va久久 | 日韩一级片在线播放 | 欧美日韩精品乱国产 | 草莓香蕉绿巨人丝瓜榴莲污在线观看 | 国产精品香蕉一区二区三区 | 婷综合 | 天天爱天天做天天爽天天躁 | 黑人干亚洲人 | 四虎一区| 国产欧美综合精品一区二区 | 69日本人xxxx16—18 | 国产二区视频 | 久久五月综合婷婷中文云霸高清 | 国产清纯女高中生在线观看 | 国产精品福利一区二区亚瑟 | 99影视在线视频免费观看 | 亚洲精品午夜在线观看 | 国产精品嫩草影院一二三区入口 | 久草在线草a免费线看 | 成年人免费看的视频 | 韩国三级年轻的小婊孑 | 日本免费v片一二三区 | 狠狠色成人综合 | 午夜影视免费 | 欧美日韩亚洲综合在线一区二区 | 日本不卡视频免费 | 国产日韩欧美在线观看不卡 | chinese一tk视频丨vk | 亚洲国产精品自产在线播放 | 国产a在线 |