diff --git a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs
index a45aab12165a51..04b27885d4d385 100644
--- a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs
@@ -18,8 +18,10 @@ public abstract class FileCleanupTestBase : IDisposable
protected static bool IsProcessElevated => s_isElevated.Value;
/// Initialize the test class base. This creates the associated test directory.
- protected FileCleanupTestBase()
+ protected FileCleanupTestBase(string tempDirectory = null)
{
+ tempDirectory ??= Path.GetTempPath();
+
// Use a unique test directory per test class. The test directory lives in the user's temp directory,
// and includes both the name of the test class and a random string. The test class name is included
// so that it can be easily correlated if necessary, and the random string to helps avoid conflicts if
@@ -31,7 +33,7 @@ protected FileCleanupTestBase()
string failure = string.Empty;
for (int i = 0; i <= 2; i++)
{
- TestDirectory = Path.Combine(Path.GetTempPath(), GetType().Name + "_" + Path.GetRandomFileName());
+ TestDirectory = Path.Combine(tempDirectory, GetType().Name + "_" + Path.GetRandomFileName());
try
{
Directory.CreateDirectory(TestDirectory);
diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs
index a92612ca0b0f4f..66646d1b3bbd99 100644
--- a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs
+++ b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs
@@ -92,7 +92,28 @@ private ClientConfigPaths(string exePath, bool includeUserConfig)
}
}
- if (!string.IsNullOrEmpty(ApplicationUri))
+ string externalConfigPath = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE") as string;
+ if (!string.IsNullOrEmpty(externalConfigPath))
+ {
+ if (Uri.IsWellFormedUriString(externalConfigPath, UriKind.Absolute))
+ {
+ Uri externalConfigUri = new Uri(externalConfigPath, UriKind.Absolute);
+ if (externalConfigUri.IsFile)
+ {
+ ApplicationConfigUri = externalConfigUri.LocalPath;
+ }
+ }
+ else
+ {
+ if (!Path.IsPathRooted(externalConfigPath))
+ {
+ externalConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, externalConfigPath);
+ }
+
+ ApplicationConfigUri = Path.GetFullPath(externalConfigPath);
+ }
+ }
+ else if (!string.IsNullOrEmpty(ApplicationUri))
{
string applicationPath = ApplicationUri;
if (isSingleFile)
diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
index 94670bcb997dfe..816d4ca00292ed 100644
--- a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
+++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
@@ -65,6 +65,7 @@
+
diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs
new file mode 100644
index 00000000000000..a802cccb393f5f
--- /dev/null
+++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs
@@ -0,0 +1,105 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Configuration;
+using System.IO;
+using System.Runtime.CompilerServices;
+using Microsoft.DotNet.RemoteExecutor;
+using Xunit;
+
+namespace System.ConfigurationTests
+{
+ public class ConfigurationPathTests : FileCleanupTestBase
+ {
+ public ConfigurationPathTests() : base(AppDomain.CurrentDomain.BaseDirectory) // We do not want the files go to temporary directory as that will not test the relative paths correctly
+ {
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void CustomAppConfigIsUsedWhenSpecifiedAsRelativePath()
+ {
+ const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified";
+ string expectedSettingValue = Guid.NewGuid().ToString();
+ string configFilePath = Path.Combine(GetTestDirectoryName(), CreateAppConfigFileWithSetting(SettingName, expectedSettingValue));
+
+ RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => {
+ // We change directory so that if product tries to read from the current directory which usually happens to be same as BaseDirectory the test will fail
+ Environment.CurrentDirectory = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".."));
+ AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath);
+ Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]);
+ }, configFilePath, expectedSettingValue).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void CustomAppConfigIsUsedWhenSpecifiedAsAbsolutePath()
+ {
+ const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified";
+ string expectedSettingValue = Guid.NewGuid().ToString();
+ string configFilePath = Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, expectedSettingValue));
+
+ RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => {
+ AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath);
+ Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]);
+ }, configFilePath, expectedSettingValue).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void CustomAppConfigIsUsedWhenSpecifiedAsAbsoluteUri()
+ {
+ const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified";
+ string expectedSettingValue = Guid.NewGuid().ToString();
+ string configFilePath = new Uri(Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, expectedSettingValue))).ToString();
+
+ RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => {
+ AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath);
+ Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]);
+ }, configFilePath, expectedSettingValue).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void NoErrorWhenCustomAppConfigIsSpecifiedAndItDoesNotExist()
+ {
+ RemoteExecutor.Invoke(() =>
+ {
+ AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "non-existing-file.config");
+ Assert.Null(ConfigurationManager.AppSettings["AnySetting"]);
+ }).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void MalformedAppConfigCausesException()
+ {
+ const string SettingName = "AnySetting";
+
+ // Following will cause malformed config file
+ string configFilePath = Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, "\""));
+
+ RemoteExecutor.Invoke((string configFilePath) => {
+ AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath);
+ Assert.Throws(() => ConfigurationManager.AppSettings[SettingName]);
+ }, configFilePath).Dispose();
+ }
+
+ private string GetTestDirectoryName()
+ {
+ string dir = TestDirectory;
+ if (dir.EndsWith("\\") || dir.EndsWith("/"))
+ dir = dir.Substring(0, dir.Length - 1);
+
+ return Path.GetFileName(dir);
+ }
+
+ private string CreateAppConfigFileWithSetting(string key, string rawUnquotedValue, [CallerMemberName] string memberName = null, [CallerLineNumber] int lineNumber = 0)
+ {
+ string fileName = GetTestFileName(null, memberName, lineNumber) + ".config";
+ File.WriteAllText(Path.Combine(TestDirectory, fileName),
+ @$"
+
+
+
+
+");
+ return fileName;
+ }
+ }
+}