From 02b2e3d02a7a320231b129b256e79c3d25a95ee6 Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Mon, 14 Sep 2015 16:28:45 -0700 Subject: [PATCH 1/4] fix #279: Revisit Key behavior --- .../IConfigurationSection.cs | 1 + .../ConfigurationBinder.cs | 7 ----- .../ConfigurationBase.cs | 4 +-- .../ConfigurationSection.cs | 30 ++++++++++++++++--- .../ArrayTests.cs | 25 +++++++++++----- .../ArrayTest.cs | 12 ++++---- .../ConfigurationTest.cs | 12 ++++---- 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSection.cs b/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSection.cs index e2781661..9f32c04a 100644 --- a/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSection.cs +++ b/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSection.cs @@ -7,6 +7,7 @@ namespace Microsoft.Framework.Configuration public interface IConfigurationSection : IConfiguration { string Key { get; } + string Path { get; } string Value { get; set; } } } diff --git a/src/Microsoft.Framework.Configuration.Binder/ConfigurationBinder.cs b/src/Microsoft.Framework.Configuration.Binder/ConfigurationBinder.cs index b9fbe90c..0ab37785 100644 --- a/src/Microsoft.Framework.Configuration.Binder/ConfigurationBinder.cs +++ b/src/Microsoft.Framework.Configuration.Binder/ConfigurationBinder.cs @@ -155,13 +155,6 @@ private static void BindDictionary(object dictionary, Type dictionaryType, IConf if (item != null) { var key = child.Key; - var section = config as IConfigurationSection; - if (section != null) - { - // Remove the parent key and : delimiter to get the configurationSection's key - key = key.Substring(section.Key.Length + 1); - } - addMethod.Invoke(dictionary, new[] { key, item }); } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs index 5786710d..9117a8d7 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs @@ -78,7 +78,7 @@ public IEnumerable GetChildren() var distinctSegments = segments.Distinct(); return distinctSegments.Select(segment => { - return new ConfigurationSection(Sources, prefix + segment); + return new ConfigurationSection(Sources, prefix, segment); }); } @@ -89,7 +89,7 @@ public IConfigurationSection GetSection(string key) throw new InvalidOperationException(Resources.Error_EmptyKey); } - return new ConfigurationSection(Sources, GetPrefix() + key); + return new ConfigurationSection(Sources, GetPrefix(), key); } protected abstract string GetPrefix(); diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs index 25e24d9f..dd9c44fc 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs @@ -10,8 +10,9 @@ namespace Microsoft.Framework.Configuration public class ConfigurationSection : ConfigurationBase, IConfigurationSection { private readonly string _key; + private readonly string _prefix; - public ConfigurationSection(IList sources, string key) + public ConfigurationSection(IList sources, string prefix, string key) : base(sources) { if (sources == null) @@ -19,6 +20,11 @@ public ConfigurationSection(IList sources, string key) throw new ArgumentNullException(nameof(sources)); } + if (prefix == null) + { + throw new ArgumentNullException(nameof(prefix)); + } + if (key == null) { throw new ArgumentNullException(nameof(key)); @@ -30,6 +36,7 @@ public ConfigurationSection(IList sources, string key) } _key = key; + _prefix = prefix; } public string Key @@ -40,6 +47,21 @@ public string Key } } + public string Path + { + get + { + if (!string.IsNullOrEmpty(_prefix)) + { + return _prefix + _key; + } + else + { + return _key; + } + } + } + public string Value { get @@ -48,7 +70,7 @@ public string Value { string value = null; - if (src.TryGet(_key, out value)) + if (src.TryGet(Path, out value)) { return value; } @@ -65,14 +87,14 @@ public string Value foreach (var src in Sources) { - src.Set(Key, value); + src.Set(Path, value); } } } protected override string GetPrefix() { - return _key + Constants.KeyDelimiter; + return Path + Constants.KeyDelimiter; } } } diff --git a/test/Microsoft.Framework.Configuration.FunctionalTests/ArrayTests.cs b/test/Microsoft.Framework.Configuration.FunctionalTests/ArrayTests.cs index 1c7f9f8b..92675f6f 100644 --- a/test/Microsoft.Framework.Configuration.FunctionalTests/ArrayTests.cs +++ b/test/Microsoft.Framework.Configuration.FunctionalTests/ArrayTests.cs @@ -62,14 +62,23 @@ public void DifferentConfigSources_Merged_KeysAreSorted() var indexConfigurationSections = configurationSection.GetChildren().ToArray(); Assert.Equal(8, indexConfigurationSections.Length); - Assert.Equal("address:0", indexConfigurationSections[0].Key); - Assert.Equal("address:1", indexConfigurationSections[1].Key); - Assert.Equal("address:2", indexConfigurationSections[2].Key); - Assert.Equal("address:3", indexConfigurationSections[3].Key); - Assert.Equal("address:4", indexConfigurationSections[4].Key); - Assert.Equal("address:i", indexConfigurationSections[5].Key); - Assert.Equal("address:j", indexConfigurationSections[6].Key); - Assert.Equal("address:x", indexConfigurationSections[7].Key); + Assert.Equal("0", indexConfigurationSections[0].Key); + Assert.Equal("1", indexConfigurationSections[1].Key); + Assert.Equal("2", indexConfigurationSections[2].Key); + Assert.Equal("3", indexConfigurationSections[3].Key); + Assert.Equal("4", indexConfigurationSections[4].Key); + Assert.Equal("i", indexConfigurationSections[5].Key); + Assert.Equal("j", indexConfigurationSections[6].Key); + Assert.Equal("x", indexConfigurationSections[7].Key); + + Assert.Equal("address:0", indexConfigurationSections[0].Path); + Assert.Equal("address:1", indexConfigurationSections[1].Path); + Assert.Equal("address:2", indexConfigurationSections[2].Path); + Assert.Equal("address:3", indexConfigurationSections[3].Path); + Assert.Equal("address:4", indexConfigurationSections[4].Path); + Assert.Equal("address:i", indexConfigurationSections[5].Path); + Assert.Equal("address:j", indexConfigurationSections[6].Path); + Assert.Equal("address:x", indexConfigurationSections[7].Path); } [Fact] diff --git a/test/Microsoft.Framework.Configuration.Json.Test/ArrayTest.cs b/test/Microsoft.Framework.Configuration.Json.Test/ArrayTest.cs index 9a808dbd..2dcce956 100644 --- a/test/Microsoft.Framework.Configuration.Json.Test/ArrayTest.cs +++ b/test/Microsoft.Framework.Configuration.Json.Test/ArrayTest.cs @@ -233,12 +233,12 @@ public void PropertiesAreSortedByNumberOnlyFirst() var indexConfigurationSections = configurationSection.GetChildren().ToArray(); Assert.Equal(6, indexConfigurationSections.Count()); - Assert.Equal("setting:4", indexConfigurationSections[0].Key); - Assert.Equal("setting:10", indexConfigurationSections[1].Key); - Assert.Equal("setting:42", indexConfigurationSections[2].Key); - Assert.Equal("setting:1text", indexConfigurationSections[3].Key); - Assert.Equal("setting:bob", indexConfigurationSections[4].Key); - Assert.Equal("setting:hello", indexConfigurationSections[5].Key); + Assert.Equal("4", indexConfigurationSections[0].Key); + Assert.Equal("10", indexConfigurationSections[1].Key); + Assert.Equal("42", indexConfigurationSections[2].Key); + Assert.Equal("1text", indexConfigurationSections[3].Key); + Assert.Equal("bob", indexConfigurationSections[4].Key); + Assert.Equal("hello", indexConfigurationSections[5].Key); } } } diff --git a/test/Microsoft.Framework.Configuration.Test/ConfigurationTest.cs b/test/Microsoft.Framework.Configuration.Test/ConfigurationTest.cs index d1a98483..9c9db794 100644 --- a/test/Microsoft.Framework.Configuration.Test/ConfigurationTest.cs +++ b/test/Microsoft.Framework.Configuration.Test/ConfigurationTest.cs @@ -189,7 +189,7 @@ public void CanGetConfigurationSection() } [Fact] - public void CanGetConfigurationSections() + public void CanGetConfigurationChildren() { // Arrange var dic1 = new Dictionary() @@ -221,11 +221,11 @@ public void CanGetConfigurationSections() // Assert Assert.Equal(2, configSections.Count()); - Assert.Equal("MemVal1", configSections.FirstOrDefault(c => c.Key == "Data:DB1")["Connection1"]); - Assert.Equal("MemVal2", configSections.FirstOrDefault(c => c.Key == "Data:DB1")["Connection2"]); - Assert.Equal("MemVal3", configSections.FirstOrDefault(c => c.Key == "Data:DB2Connection").Value); - Assert.False(configSections.Exists(c => c.Key == "Data:DB3")); - Assert.False(configSections.Exists(c => c.Key == "Source:DB3")); + Assert.Equal("MemVal1", configSections.FirstOrDefault(c => c.Key == "DB1")["Connection1"]); + Assert.Equal("MemVal2", configSections.FirstOrDefault(c => c.Key == "DB1")["Connection2"]); + Assert.Equal("MemVal3", configSections.FirstOrDefault(c => c.Key == "DB2Connection").Value); + Assert.False(configSections.Exists(c => c.Key == "DB3")); + Assert.False(configSections.Exists(c => c.Key == "DB3")); } [Fact] From 4704d41f62009f9f2c9b7d9b7d50b6607b92501f Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Thu, 17 Sep 2015 10:48:16 -0700 Subject: [PATCH 2/4] PR changes --- .../ConfigurationBase.cs | 28 ++++++++++++------- .../ConfigurationRoot.cs | 13 +++++---- .../ConfigurationSection.cs | 28 ++++++------------- .../Resources.resx | 2 +- 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs index 9117a8d7..20d4d63a 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs @@ -21,13 +21,15 @@ public ConfigurationBase(IList sources) _sources = sources; } + public virtual string Path { get; set; } + public string this[string key] { get { if (string.IsNullOrEmpty(key)) { - throw new InvalidOperationException(Resources.Error_EmptyKey); + throw new ArgumentException(Resources.Error_EmptyKey); } // If a key in the newly added configuration source is identical to a key in a @@ -37,7 +39,7 @@ public string this[string key] { string value = null; - if (src.TryGet(GetPrefix() + key, out value)) + if (src.TryGet(GetPath() + key, out value)) { return value; } @@ -54,7 +56,7 @@ public string this[string key] foreach (var src in Sources) { - src.Set(GetPrefix() + key, value); + src.Set(GetPath() + key, value); } } } @@ -69,16 +71,14 @@ public IList Sources public IEnumerable GetChildren() { - var prefix = GetPrefix(); - var segments = Sources.Aggregate( Enumerable.Empty(), - (seed, source) => source.ProduceConfigurationSections(seed, prefix, Constants.KeyDelimiter)); + (seed, source) => source.ProduceConfigurationSections(seed, GetPath(), Constants.KeyDelimiter)); var distinctSegments = segments.Distinct(); return distinctSegments.Select(segment => { - return new ConfigurationSection(Sources, prefix, segment); + return new ConfigurationSection(Sources, GetPath(), segment); }); } @@ -86,12 +86,20 @@ public IConfigurationSection GetSection(string key) { if (string.IsNullOrEmpty(key)) { - throw new InvalidOperationException(Resources.Error_EmptyKey); + throw new ArgumentException(Resources.Error_EmptyKey); } - return new ConfigurationSection(Sources, GetPrefix(), key); + return new ConfigurationSection(Sources, GetPath(), key); } - protected abstract string GetPrefix(); + private string GetPath() + { + if (!string.IsNullOrEmpty(Path)) + { + return Path + Constants.KeyDelimiter; + } + + return Path; + } } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationRoot.cs b/src/Microsoft.Framework.Configuration/ConfigurationRoot.cs index 98c56d0b..746411e2 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationRoot.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationRoot.cs @@ -17,17 +17,20 @@ public ConfigurationRoot(IList sources) } } - public void Reload() + public override string Path { - foreach (var src in Sources) + get { - src.Load(); + return string.Empty; } } - protected override string GetPrefix() + public void Reload() { - return string.Empty; + foreach (var src in Sources) + { + src.Load(); + } } } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs index dd9c44fc..aa4e6264 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs @@ -10,9 +10,9 @@ namespace Microsoft.Framework.Configuration public class ConfigurationSection : ConfigurationBase, IConfigurationSection { private readonly string _key; - private readonly string _prefix; + private readonly string _parentPath; - public ConfigurationSection(IList sources, string prefix, string key) + public ConfigurationSection(IList sources, string parentPath, string key) : base(sources) { if (sources == null) @@ -20,23 +20,18 @@ public ConfigurationSection(IList sources, string prefix, throw new ArgumentNullException(nameof(sources)); } - if (prefix == null) + if (parentPath == null) { - throw new ArgumentNullException(nameof(prefix)); - } - - if (key == null) - { - throw new ArgumentNullException(nameof(key)); + throw new ArgumentNullException(nameof(parentPath)); } if (string.IsNullOrEmpty(key)) { - throw new InvalidOperationException(Resources.Error_EmptyKey); + throw new ArgumentException(Resources.Error_EmptyKey); } _key = key; - _prefix = prefix; + _parentPath = parentPath; } public string Key @@ -47,13 +42,13 @@ public string Key } } - public string Path + public override string Path { get { - if (!string.IsNullOrEmpty(_prefix)) + if (!string.IsNullOrEmpty(_parentPath)) { - return _prefix + _key; + return _parentPath + _key; } else { @@ -91,10 +86,5 @@ public string Value } } } - - protected override string GetPrefix() - { - return Path + Constants.KeyDelimiter; - } } } diff --git a/src/Microsoft.Framework.Configuration/Resources.resx b/src/Microsoft.Framework.Configuration/Resources.resx index 947d6a27..fb7badd0 100644 --- a/src/Microsoft.Framework.Configuration/Resources.resx +++ b/src/Microsoft.Framework.Configuration/Resources.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Empty key is not allowed. + Empty or null key is not allowed. Reload can only be called on top-level configuration element From 3523969dedc7fb66f378f97ee58cda6779cc1263 Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Thu, 17 Sep 2015 20:26:37 -0700 Subject: [PATCH 3/4] Changes --- .../ConfigurationBase.cs | 14 +++++------ .../ConfigurationSection.cs | 24 +++++++++---------- .../ConfigurationSource.cs | 2 ++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs index 20d4d63a..043a7201 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs @@ -21,7 +21,7 @@ public ConfigurationBase(IList sources) _sources = sources; } - public virtual string Path { get; set; } + public abstract string Path { get; } public string this[string key] { @@ -39,7 +39,7 @@ public string this[string key] { string value = null; - if (src.TryGet(GetPath() + key, out value)) + if (src.TryGet(GetPrefix() + key, out value)) { return value; } @@ -56,7 +56,7 @@ public string this[string key] foreach (var src in Sources) { - src.Set(GetPath() + key, value); + src.Set(GetPrefix() + key, value); } } } @@ -73,12 +73,12 @@ public IEnumerable GetChildren() { var segments = Sources.Aggregate( Enumerable.Empty(), - (seed, source) => source.ProduceConfigurationSections(seed, GetPath(), Constants.KeyDelimiter)); + (seed, source) => source.ProduceConfigurationSections(seed, Path, Constants.KeyDelimiter)); var distinctSegments = segments.Distinct(); return distinctSegments.Select(segment => { - return new ConfigurationSection(Sources, GetPath(), segment); + return new ConfigurationSection(Sources, Path, segment); }); } @@ -89,10 +89,10 @@ public IConfigurationSection GetSection(string key) throw new ArgumentException(Resources.Error_EmptyKey); } - return new ConfigurationSection(Sources, GetPath(), key); + return new ConfigurationSection(Sources, Path, key); } - private string GetPath() + private string GetPrefix() { if (!string.IsNullOrEmpty(Path)) { diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs index aa4e6264..7949d953 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs @@ -10,7 +10,7 @@ namespace Microsoft.Framework.Configuration public class ConfigurationSection : ConfigurationBase, IConfigurationSection { private readonly string _key; - private readonly string _parentPath; + private readonly string _path; public ConfigurationSection(IList sources, string parentPath, string key) : base(sources) @@ -31,7 +31,14 @@ public ConfigurationSection(IList sources, string parentPa } _key = key; - _parentPath = parentPath; + if (!string.IsNullOrEmpty(parentPath)) + { + _path = parentPath + Constants.KeyDelimiter + key; + } + else + { + _path = key; + } } public string Key @@ -46,14 +53,7 @@ public override string Path { get { - if (!string.IsNullOrEmpty(_parentPath)) - { - return _parentPath + _key; - } - else - { - return _key; - } + return _path; } } @@ -65,7 +65,7 @@ public string Value { string value = null; - if (src.TryGet(Path, out value)) + if (src.TryGet(_path, out value)) { return value; } @@ -82,7 +82,7 @@ public string Value foreach (var src in Sources) { - src.Set(Path, value); + src.Set(_path, value); } } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSource.cs b/src/Microsoft.Framework.Configuration/ConfigurationSource.cs index eff84ec5..4e37da51 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSource.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSource.cs @@ -35,6 +35,8 @@ public virtual IEnumerable ProduceConfigurationSections( string prefix, string delimiter) { + prefix = prefix + delimiter; + return Data .Where(kv => kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) .Select(kv => Segment(kv.Key, prefix, delimiter)) From aed3438b0e34026456b122fb6e4baf4c2ff4438b Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Sun, 20 Sep 2015 18:36:27 -0700 Subject: [PATCH 4/4] changes --- .../IConfigurationSource.cs | 2 +- .../ConfigurationBase.cs | 45 +------------------ .../ConfigurationSection.cs | 11 ++--- .../ConfigurationSource.cs | 14 +++--- 4 files changed, 13 insertions(+), 59 deletions(-) diff --git a/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSource.cs b/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSource.cs index eab05251..85ce9211 100644 --- a/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSource.cs +++ b/src/Microsoft.Framework.Configuration.Abstractions/IConfigurationSource.cs @@ -15,7 +15,7 @@ public interface IConfigurationSource IEnumerable ProduceConfigurationSections( IEnumerable earlierKeys, - string prefix, + string parentPath, string delimiter); } } \ No newline at end of file diff --git a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs index 043a7201..558f79da 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationBase.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationBase.cs @@ -27,37 +27,11 @@ public string this[string key] { get { - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentException(Resources.Error_EmptyKey); - } - - // 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()) - { - string value = null; - - if (src.TryGet(GetPrefix() + key, out value)) - { - return value; - } - } - - return null; + return GetSection(key).Value; } set { - if (!Sources.Any()) - { - throw new InvalidOperationException(Resources.Error_NoSources); - } - - foreach (var src in Sources) - { - src.Set(GetPrefix() + key, value); - } + GetSection(key).Value = value; } } @@ -84,22 +58,7 @@ public IEnumerable GetChildren() public IConfigurationSection GetSection(string key) { - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentException(Resources.Error_EmptyKey); - } - return new ConfigurationSection(Sources, Path, key); } - - private string GetPrefix() - { - if (!string.IsNullOrEmpty(Path)) - { - return Path + Constants.KeyDelimiter; - } - - return Path; - } } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs index 7949d953..14d466ed 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSection.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSection.cs @@ -15,11 +15,6 @@ public class ConfigurationSection : ConfigurationBase, IConfigurationSection public ConfigurationSection(IList sources, string parentPath, string key) : base(sources) { - if (sources == null) - { - throw new ArgumentNullException(nameof(sources)); - } - if (parentPath == null) { throw new ArgumentNullException(nameof(parentPath)); @@ -31,7 +26,7 @@ public ConfigurationSection(IList sources, string parentPa } _key = key; - if (!string.IsNullOrEmpty(parentPath)) + if (!string.Equals(parentPath, string.Empty)) { _path = parentPath + Constants.KeyDelimiter + key; } @@ -65,7 +60,7 @@ public string Value { string value = null; - if (src.TryGet(_path, out value)) + if (src.TryGet(Path, out value)) { return value; } @@ -82,7 +77,7 @@ public string Value foreach (var src in Sources) { - src.Set(_path, value); + src.Set(Path, value); } } } diff --git a/src/Microsoft.Framework.Configuration/ConfigurationSource.cs b/src/Microsoft.Framework.Configuration/ConfigurationSource.cs index 4e37da51..89a08d19 100644 --- a/src/Microsoft.Framework.Configuration/ConfigurationSource.cs +++ b/src/Microsoft.Framework.Configuration/ConfigurationSource.cs @@ -32,22 +32,22 @@ public virtual void Load() public virtual IEnumerable ProduceConfigurationSections( IEnumerable earlierKeys, - string prefix, + string parentPath, string delimiter) { - prefix = prefix + delimiter; + parentPath = parentPath + delimiter; return Data - .Where(kv => kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) - .Select(kv => Segment(kv.Key, prefix, delimiter)) + .Where(kv => kv.Key.StartsWith(parentPath, StringComparison.OrdinalIgnoreCase)) + .Select(kv => Segment(kv.Key, parentPath, delimiter)) .Concat(earlierKeys) .OrderBy(k => k, ConfigurationKeyComparer.Instance); } - private static string Segment(string key, string prefix, string delimiter) + private static string Segment(string key, string parentPath, string delimiter) { - var indexOf = key.IndexOf(delimiter, prefix.Length, StringComparison.OrdinalIgnoreCase); - return indexOf < 0 ? key.Substring(prefix.Length) : key.Substring(prefix.Length, indexOf - prefix.Length); + var indexOf = key.IndexOf(delimiter, parentPath.Length, StringComparison.OrdinalIgnoreCase); + return indexOf < 0 ? key.Substring(parentPath.Length) : key.Substring(parentPath.Length, indexOf - parentPath.Length); } } }