导航

04-008 Configuration 之 Configuration

Posted on 2015-03-17 13:02  DotNet1010  阅读(247)  评论(0)    收藏  举报

 Configuration 实现了两个接口  IConfiguration 和 IConfigurationSourceContainer

 前文中 IConfigurationSourceContainer 的扩展方法 也就等同于Configuration的扩展方法。

 最最重要的方法:

   private readonly IList<IConfigurationSource> _sources = new List<IConfigurationSource>();
   private readonly IList<ICommitableConfigurationSource> _committableSources = new List<ICommitableConfigurationSource>();
   public IConfigurationSourceContainer Add(IConfigurationSource configurationSource)
        {
            configurationSource.Load();
            return AddLoadedSource(configurationSource);
        }

        internal IConfigurationSourceContainer AddLoadedSource(IConfigurationSource configurationSource)
        {
            _sources.Add(configurationSource);

            if (configurationSource is ICommitableConfigurationSource)
            {
                _committableSources.Add(configurationSource as ICommitableConfigurationSource);
            }
            return this;
        }

 实现IConfigurationSource 的有前文中的 IniFile;Json;Xml;CommandLine;EnvironmentVariables;另外还有一个 MemoryConfigurationSource;

如果添加了多个 且具有相同的Key; 如何取值呢? 答案是最后添加的。 代码如下:

 public bool TryGet(string key, out string value)
        {
            if (key == null) throw new ArgumentNullException("key");

            // If a key in the newly added configuration source is identical to a key in a 
            // formerly added configuration source, the new one overrides the former one.
            // So we search in reverse order, starting with latest configuration source.
            foreach (var src in _sources.Reverse())
            {
                if (src.TryGet(key, out value))
                {
                    return true;
                }
            }
            value = null;
            return false;
        }

 赋值则是每一个都进行赋值:代码如下:

        public void Set(string key, string value)
        {
            if (key == null) throw new ArgumentNullException("key");
            if (value == null) throw new ArgumentNullException("value");

            foreach (var src in _sources)
            {
                src.Set(key, value);
            }
        }

 Reload 是每一个都加载:

        public void Reload()
        {
            foreach (var src in _sources)
            {
                src.Load();
            }
        }

 提交保存则是只保存最后一个可以保存的ConfigurationSource 可以保存的有 IniFile Json  Xml;

         public void Commit()
        {
            var final = _committableSources.LastOrDefault();
            if (final == null)
            {
                throw new InvalidOperationException(Resources.Error_NoCommitableSource);
            }
            final.Commit();
        }

GetSubKey 则通过前缀 创建 实现IConfiguration的 ConfigurationFocus 代码如下:

       public IConfiguration GetSubKey(string key)
        {
            return new ConfigurationFocus(this, key + Constants.KeyDelimiter);
        }

  {"Data:DB1:Connection1", "MemVal1"}  调用  GetSubKey("Data")   则变成 {DB1:Connection1", "MemVal1"}

 理解一下下面的代码:

        public IEnumerable<KeyValuePair<string, IConfiguration>> GetSubKeys(string key)
        {
            if (key == null) throw new ArgumentNullException("key");

            return GetSubKeysImplementation(key + Constants.KeyDelimiter);
        }

        private IEnumerable<KeyValuePair<string, IConfiguration>> GetSubKeysImplementation(string prefix)
        {
            var segments = _sources.Aggregate(
                Enumerable.Empty<string>(),
                (seed, source) => source.ProduceSubKeys(seed, prefix, Constants.KeyDelimiter));

            var distinctSegments = segments.Distinct();

            return distinctSegments.Select(segment => CreateConfigurationFocus(prefix, segment));
        }
        private KeyValuePair<string, IConfiguration> CreateConfigurationFocus(string prefix, string segment)
        {
            return new KeyValuePair<string, IConfiguration>(
                segment,
                new ConfigurationFocus(this, prefix + segment + Constants.KeyDelimiter));
        }

 看一下单元测试代码(下方代码):

segments  包含 三个值:”DB2Connection“,"DB1",”DB1“

distinctSegments 只有 ”DB2Connection“,"DB1"

 结果如下:

"DB2Connection"------------new ConfigurationFocus(this, "Data:"+ "DB2Connection:");

"DB1"                ------------new ConfigurationFocus(this, "Data:"+ "DB1:");

 

  public void CanGetSubKeys()
        {
            // Arrange
            var dic1 = new Dictionary<string, string>()
                {
                    {"Data:DB1:Connection1", "MemVal1"},
                    {"Data:DB1:Connection2", "MemVal2"}
                };
            var dic2 = new Dictionary<string, string>()
                {
                    {"Data:DB2Connection", "MemVal3"}
                };
            var dic3 = new Dictionary<string, string>()
                {
                    {"DataSource:DB3:Connection", "MemVal4"}
                };
            var memConfigSrc1 = new MemoryConfigurationSource(dic1);
            var memConfigSrc2 = new MemoryConfigurationSource(dic2);
            var memConfigSrc3 = new MemoryConfigurationSource(dic3);

            var config = new Configuration();
            config.AddLoadedSource(memConfigSrc1);
            config.AddLoadedSource(memConfigSrc2);
            config.AddLoadedSource(memConfigSrc3);

            // Act
            var configFocusList = config.GetSubKeys("Data");
            var subKeysSet = configFocusList.ToDictionary(e => e.Key, e => e.Value);

            // Assert
            Assert.Equal(2, configFocusList.Count());
            Assert.Equal("MemVal1", subKeysSet["DB1"].Get("Connection1"));
            Assert.Equal("MemVal2", subKeysSet["DB1"].Get("Connection2"));
            Assert.Equal("MemVal3", subKeysSet["DB2Connection"].Get(null));
            Assert.False(subKeysSet.ContainsKey("DB3"));
            Assert.False(subKeysSet.ContainsKey("Source:DB3"));
        }