Skip to content

Commit

Permalink
Remove LINQ per dotnet#44923
Browse files Browse the repository at this point in the history
  • Loading branch information
Emzi0767 committed Dec 20, 2020
1 parent 7f8a0a2 commit ffac54b
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Extensions.Configuration.EnvironmentVariables
{
Expand All @@ -18,112 +17,91 @@ public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider
private const string SqlServerPrefix = "SQLCONNSTR_";
private const string CustomPrefix = "CUSTOMCONNSTR_";

private const string ConnStrKeyFormat = "ConnectionStrings:{0}";
private const string ProviderKeyFormat = "ConnectionStrings:{0}_ProviderName";

private readonly string _prefix;

/// <summary>
/// Initializes a new instance.
/// </summary>
public EnvironmentVariablesConfigurationProvider() : this(string.Empty)
{ }
public EnvironmentVariablesConfigurationProvider() =>
_prefix = 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;
}

/// <summary>
/// Loads the environment variables.
/// </summary>
public override void Load()
{
public override void Load() =>
Load(Environment.GetEnvironmentVariables());
}

internal void Load(IDictionary envVariables)
{
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

IEnumerable<DictionaryEntry> filteredEnvVariables = envVariables
.Cast<DictionaryEntry>()
.SelectMany(x => AzureEnvToAppEnv(x, _prefix));

foreach (DictionaryEntry envVariable in filteredEnvVariables)
foreach (DictionaryEntry entry in envVariables)
{
string key = envVariable.Key as string;
if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase))
key = key.Substring(_prefix.Length);

data[key] = (string)envVariable.Value;
string key = entry.Key as string;
string provider = null;
string prefix;

if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = MySqlServerPrefix;
provider = "MySql.Data.MySqlClient";
}
else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlAzureServerPrefix;
provider = "System.Data.SqlClient";
}
else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlServerPrefix;
provider = "System.Data.SqlClient";
}
else if (key.StartsWith(CustomPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = CustomPrefix;
}
else if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase))
{
// This prevents the prefix from being normalized.
// We can also do a fast path branch, I guess? No point in reallocating if the prefix is empty.
key = NormalizeKey(key.Substring(_prefix.Length));
data[key] = entry.Value as string;

continue;
}
else
{
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);
}
}

Data = data;
}

private static string NormalizeKey(string key)
private void AddIfPrefixed(Dictionary<string, string> data, string key, string value)
{
return key.Replace("__", ConfigurationPath.KeyDelimiter);
}

private static IEnumerable<DictionaryEntry> AzureEnvToAppEnv(DictionaryEntry entry, string envPrefix)
{
string key = (string)entry.Key;
string prefix = string.Empty;
string provider = string.Empty;

if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase))
if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase))
{
prefix = MySqlServerPrefix;
provider = "MySql.Data.MySqlClient";
}
else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlAzureServerPrefix;
provider = "System.Data.SqlClient";
}
else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = SqlServerPrefix;
provider = "System.Data.SqlClient";
}
else if (key.StartsWith(CustomPrefix, StringComparison.OrdinalIgnoreCase))
{
prefix = CustomPrefix;
}
else if (key.StartsWith(envPrefix, StringComparison.OrdinalIgnoreCase))
{
// This prevents the prefix from being normalized.
// We can also do a fast path branch, I guess? No point in reallocating if the prefix is empty.
entry.Key = envPrefix != string.Empty
? envPrefix + NormalizeKey(key.Substring(envPrefix.Length))
: NormalizeKey(key);

yield return entry;
yield break;
}
else
{
yield break;
}

// Return the key-value pair for connection string
yield return new DictionaryEntry(
string.Format(ConnStrKeyFormat, NormalizeKey(key.Substring(prefix.Length))),
entry.Value);

if (!string.IsNullOrEmpty(provider))
{
// Return the key-value pair for provider name
yield return new DictionaryEntry(
string.Format(ProviderKeyFormat, NormalizeKey(key.Substring(prefix.Length))),
provider);
key = key.Substring(_prefix.Length);
data[key] = value;
}
}

private static string NormalizeKey(string key) => key.Replace("__", ConfigurationPath.KeyDelimiter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,14 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariables()
var dict = new Hashtable()
{
{"data__ConnectionString", "connection"},
{"SQLCONNSTR__db1", "connStr"}
{"SQLCONNSTR_db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider();

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("data:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:db1_ProviderName"));
}

[Fact]
Expand All @@ -159,14 +159,30 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotPrefix()
var dict = new Hashtable()
{
{"test__prefix__with__double__underscores__data__ConnectionString", "connection"},
{"SQLCONNSTR__db1", "connStr"}
{"SQLCONNSTR_db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("test__prefix__with__double__underscores__");

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("data:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:db1_ProviderName"));
}

[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotInAnomalousPrefix()
{
var dict = new Hashtable()
{
{"_____EXPERIMENTAL__data__ConnectionString", "connection"},
{"SQLCONNSTR_db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("_____EXPERIMENTAL__");

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("data:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:db1_ProviderName"));
}

[Fact]
Expand All @@ -175,14 +191,14 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariablesWithDuplicatedPrefix()
var dict = new Hashtable()
{
{"test__test__ConnectionString", "connection"},
{"SQLCONNSTR__db1", "connStr"}
{"SQLCONNSTR_db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("test__");

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("test:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:db1_ProviderName"));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
Expand Down

0 comments on commit ffac54b

Please sign in to comment.