未验证 提交 9cd49ff7 编写于 作者: D David Edey 提交者: GitHub

Improves handling of env prefixes containing __ (#65757)

Both the un-altered and colon-normalized prefixes now match
environment variables in either the __ or colon formats.

The change includes minor refactors to
the EnvironmentVariablesConfigurationProvider
to make the code easier to follow and reduce the likelihood
of future regressions.

Test naming has been made clearer, and a comprehensive test
has been added.

Fix #65756
上级 195c7e21
......@@ -15,22 +15,29 @@ public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider
private const string MySqlServerPrefix = "MYSQLCONNSTR_";
private const string SqlAzureServerPrefix = "SQLAZURECONNSTR_";
private const string SqlServerPrefix = "SQLCONNSTR_";
private const string CustomPrefix = "CUSTOMCONNSTR_";
private const string CustomConnectionStringPrefix = "CUSTOMCONNSTR_";
private readonly string _prefix;
private readonly string _normalizedPrefix;
/// <summary>
/// Initializes a new instance.
/// </summary>
public EnvironmentVariablesConfigurationProvider() =>
public EnvironmentVariablesConfigurationProvider()
{
_prefix = string.Empty;
_normalizedPrefix = string.Empty;
}
/// <summary>
/// Initializes a new instance with the specified prefix.
/// </summary>
/// <param name="prefix">A prefix used to filter the environment variables.</param>
public EnvironmentVariablesConfigurationProvider(string? prefix) =>
public EnvironmentVariablesConfigurationProvider(string? prefix)
{
_prefix = prefix ?? string.Empty;
_normalizedPrefix = Normalize(_prefix);
}
/// <summary>
/// Loads the environment variables.
......@@ -54,42 +61,28 @@ internal void Load(IDictionary envVariables)
{
while (e.MoveNext())
{
DictionaryEntry entry = e.Entry;
string key = (string)entry.Key;
string? provider = null;
string prefix;
string key = (string)e.Entry.Key;
string? value = (string?)e.Entry.Value;
if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = MySqlServerPrefix;
provider = "MySql.Data.MySqlClient";
HandleMatchedConnectionStringPrefix(data, MySqlServerPrefix, "MySql.Data.MySqlClient", key, value);
}
else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlAzureServerPrefix;
provider = "System.Data.SqlClient";
HandleMatchedConnectionStringPrefix(data, SqlAzureServerPrefix, "System.Data.SqlClient", key, value);
}
else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlServerPrefix;
provider = "System.Data.SqlClient";
HandleMatchedConnectionStringPrefix(data, SqlServerPrefix, "System.Data.SqlClient", key, value);
}
else if (key.StartsWith(CustomPrefix, StringComparison.OrdinalIgnoreCase))
else if (key.StartsWith(CustomConnectionStringPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = CustomPrefix;
HandleMatchedConnectionStringPrefix(data, CustomConnectionStringPrefix, null, key, value);
}
else
{
AddIfPrefixed(data, NormalizeKey(key), (string?)entry.Value);
continue;
}
// Add the key-value pair for connection string, and optionally provider name
key = NormalizeKey(key.Substring(prefix.Length));
AddIfPrefixed(data, $"ConnectionStrings:{key}", (string?)entry.Value);
if (provider != null)
{
AddIfPrefixed(data, $"ConnectionStrings:{key}_ProviderName", provider);
AddIfNormalizedKeyMatchesPrefix(data, Normalize(key), value);
}
}
}
......@@ -101,15 +94,26 @@ internal void Load(IDictionary envVariables)
Data = data;
}
private void AddIfPrefixed(Dictionary<string, string?> data, string key, string? value)
private void HandleMatchedConnectionStringPrefix(Dictionary<string, string?> data, string connectionStringPrefix, string? provider, string fullKey, string? value)
{
string normalizedKeyWithoutConnectionStringPrefix = Normalize(fullKey.Substring(connectionStringPrefix.Length));
// Add the key-value pair for connection string, and optionally provider name
AddIfNormalizedKeyMatchesPrefix(data, $"ConnectionStrings:{normalizedKeyWithoutConnectionStringPrefix}", value);
if (provider != null)
{
AddIfNormalizedKeyMatchesPrefix(data, $"ConnectionStrings:{normalizedKeyWithoutConnectionStringPrefix}_ProviderName", provider);
}
}
private void AddIfNormalizedKeyMatchesPrefix(Dictionary<string, string?> data, string normalizedKey, string? value)
{
if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase))
if (normalizedKey.StartsWith(_normalizedPrefix, StringComparison.OrdinalIgnoreCase))
{
key = key.Substring(_prefix.Length);
data[key] = value;
data[normalizedKey.Substring(_normalizedPrefix.Length)] = value;
}
}
private static string NormalizeKey(string key) => key.Replace("__", ConfigurationPath.KeyDelimiter);
private static string Normalize(string key) => key.Replace("__", ConfigurationPath.KeyDelimiter);
}
}
......@@ -156,7 +156,7 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariables()
}
[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotPrefix()
public void ReplaceDoubleUnderscoreInEnvironmentVariablesDoubleUnderscorePrefixStillMatches()
{
var dict = new Hashtable()
{
......@@ -166,11 +166,11 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotPrefix()
envConfigSrc.Load(dict);
Assert.Throws<InvalidOperationException>(() => envConfigSrc.Get("data:ConnectionString"));
Assert.Equal("connection", envConfigSrc.Get("data:ConnectionString"));
}
[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotInAnomalousPrefix()
public void MixingPathSeparatorsInPrefixStillMatchesEnvironmentVariable()
{
var dict = new Hashtable()
{
......@@ -184,7 +184,7 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotInAnomalousPrefix
}
[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesWithDuplicatedPrefix()
public void OnlyASinglePrefixIsRemovedFromMatchingKey()
{
var dict = new Hashtable()
{
......@@ -194,7 +194,29 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariablesWithDuplicatedPrefix()
envConfigSrc.Load(dict);
Assert.Throws<InvalidOperationException>(() => envConfigSrc.Get("test:ConnectionString"));
Assert.Equal("connection", envConfigSrc.Get("test:ConnectionString"));
}
[Fact]
public void OnlyEnvironmentVariablesMatchingTheGivenPrefixAreIncluded()
{
var dict = new Hashtable()
{
{"projectA__section1__project", "A"},
{"projectA__section1__projectA", "true"},
{"projectB__section1__project", "B"},
{"projectB__section1__projectB", "true"},
{"section1__project", "unknown"},
{"section1__noProject", "true"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("projectB__");
envConfigSrc.Load(dict);
Assert.Equal("B", envConfigSrc.Get("section1:project"));
Assert.Equal("true", envConfigSrc.Get("section1:projectB"));
Assert.Throws<InvalidOperationException>(() => envConfigSrc.Get("section1:projectA"));
Assert.Throws<InvalidOperationException>(() => envConfigSrc.Get("section1:noProject"));
}
[Fact]
......@@ -220,7 +242,7 @@ public class SettingsWithFoo
}
[Fact]
public void AddEnvironmentVariables_Bind_PrefixShouldNormalize()
public void AddEnvironmentVariablesUsingNormalizedPrefix_Bind_PrefixMatches()
{
try
{
......@@ -241,7 +263,7 @@ public void AddEnvironmentVariables_Bind_PrefixShouldNormalize()
}
[Fact]
public void AddEnvironmentVariables_UsingDoubleUnderscores_Bind_PrefixWontNormalize()
public void AddEnvironmentVariablesUsingPrefixWithDoubleUnderscores_Bind_PrefixMatches()
{
try
{
......@@ -253,7 +275,7 @@ public void AddEnvironmentVariables_UsingDoubleUnderscores_Bind_PrefixWontNormal
var settingsWithFoo = new SettingsWithFoo();
configuration.Bind(settingsWithFoo);
Assert.Null(settingsWithFoo.Foo);
Assert.Equal("myFooValue", settingsWithFoo.Foo);
}
finally
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册