There's a related answer here where @DeepSpace101 mentions:
Also, the location of app.config at runtime is different than what was in .net framework, instead of "projectName.exe.config". It is now "projectName.dll.config" in .net core.
I recently ran into this problem after migrating some WinForms apps from .NET Framework 4.8 to .NET 7. I noticed that all my settings were returning default values even when the .exe.config file contained an explicit override value. I first tried to see which config file the app was loading based on this answer, but AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
isn't available in .NET "Core". Then based on another answer, I checked ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath
, which confirmed the app was loading from projectName.dll.config instead of projectName.exe.config.
Fortunately, I found a good workaround based on this answer and this GitHub issue. ConfigurationManager supports an APP_CONFIG_FILE key for AppDomain.SetData
to override the .config file as long as it is called before any ConfigurationManager code is executed. I've made a utility function that I call from all of my WinForms .exes as the first line in their Program's Main()
entry point:
/// <summary>
/// Overrides .NET's Core's ConfigurationManager to use AppName.exe.config instead
/// of AppName.dll.config.
/// </summary>
/// <param name="exeConfigName">An optional name of an .exe.config file to use.
/// If null, then the entry assembly's file name without extension is used with
/// ".exe.config" appended.</param>
/// <remarks>
/// For this to take effect, this method must be called before any application code
/// pulls a configuration value.
/// </remarks>
public static void UseExeConfig(string? exeConfigName = null)
{
// .NET Framework and Core support using APP_CONFIG_FILE to override which .config
// file an app reads its settings from.
// https://github.com/dotnet/runtime/pull/56748#discussion_r682287640
//
// Note 1: This .exe.config override only affects some sections of the file. Anything
// read by the CLR host before the app starts (e.g., settings in the <runtime> section
// like <gcServer>) will only be read from the app's default config file.
// https://stackoverflow.com/questions/1838619/relocating-app-config-file-to-a-custom-path/12708388#12708388
// However, that's only an issue for .NET Framework since .NET Core reads its CLR host
// runtime settings from other places. https://learn.microsoft.com/en-us/dotnet/core/runtime-config/
//
// Note 2: We have to be careful to only reference base CLR methods here and not use
// anything from referenced assemblies. If we run any code that pulls a configuration
// setting before we change APP_CONFIG_FILE, then our change will be ignored.
string? entryAssemblyLocation = Assembly.GetEntryAssembly()?.Location;
if (entryAssemblyLocation != null)
{
string entryAssemblyFile = Path.GetFileName(entryAssemblyLocation);
string entryConfigName = entryAssemblyFile + ".config";
exeConfigName ??= Path.GetFileNameWithoutExtension(entryAssemblyFile) + ".exe.config";
if (!entryConfigName.Equals(exeConfigName, StringComparison.OrdinalIgnoreCase))
{
string basePath = Path.GetDirectoryName(entryAssemblyLocation) ?? string.Empty;
string exeConfigFilePath = Path.Combine(basePath, exeConfigName);
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", exeConfigFilePath);
}
}
}
This technique can also be used to force multiple applications to share a single .config file. For example, if you want Service.exe and Worker.exe to both look at Service.exe.config, then call UseExeConfig("Service.exe.config")
from each of their Main methods. That allows IT/Support to only have to configure connection strings in one place.