OS: RH Linux
Framework: .Net Core 2.0
I have a .dll compiled on windows in .net 4.5.2 and written in C#, called from Linux.
I use the code below to inject an app.config file into the system, like so:
```c#
var config_proxy = new ConfigurationProxy("my.dll");
config_proxy.InjectToConfigurationManager();
However, when run in Linux, I get the following exception:
"Operation is not supported on this platform."
" at System.Configuration.ClientConfigPaths..ctor(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigPaths.GetPaths(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigurationHost.get_ConfigPaths()
at System.Configuration.ClientConfigurationHost.GetStreamName(String configPath)
at System.Configuration.ClientConfigurationHost.get_IsAppConfigHttp()
at System.Configuration.ClientConfigurationSystem..ctor()
at System.Configuration.ConfigurationManager.EnsureConfigurationSystem()"
I've looked at the source [here](https://github.com/dotnet/corefx/tree/master/src/System.Configuration.ConfigurationManager/src/System/Configuration), and can see where the throw is, but can't figure out how to get it working ...
```c#
public sealed class ConfigurationProxy : IInternalConfigSystem
{
Configuration config;
Dictionary<string, IConfigurationSectionHandler> customSections;
public ConfigurationProxy(string fileName)
{
customSections = new Dictionary<string, IConfigurationSectionHandler>();
if (!Load(fileName))
throw new ConfigurationErrorsException(string.Format(
"File: {0} could not be found or was not a valid cofiguration file.",
config.FilePath));
}
private bool Load(string file)
{
config = ConfigurationManager.OpenExeConfiguration(file);
return config.HasFile;
}
public Configuration Configuration
{
get { return config; }
}
#region IInternalConfigSystem Members
public object GetSection(string configKey)
{
if (configKey == "appSettings")
return BuildAppSettings();
object sect = config.GetSection(configKey);
if (customSections.ContainsKey(configKey) && sect != null)
{
var xml = new XmlDocument();
xml.LoadXml(((ConfigurationSection)sect).SectionInformation.GetRawXml());
sect = customSections[configKey].Create(config,
config.EvaluationContext,
xml.FirstChild);
}
return sect;
}
public void RefreshConfig(string sectionName)
{
Load(config.FilePath);
}
public bool SupportsUserConfig
{
get { return false; }
}
#endregion
private NameValueCollection BuildAppSettings()
{
var coll = new NameValueCollection();
foreach (var key in config.AppSettings.Settings.AllKeys)
coll.Add(key, config.AppSettings.Settings[key].Value);
return coll;
}
public bool InjectToConfigurationManager()
{
var configSystem = typeof(ConfigurationManager).GetField("s_configSystem",
BindingFlags.Static | BindingFlags.NonPublic);
configSystem.SetValue(null, this);
if (ConfigurationManager.AppSettings.Count == config.AppSettings.Settings.Count)
return true;
return false;
}
}
I also experimented with using mapped config, e.g.:
```c#
var map = new ExeConfigurationFileMap { ExeConfigFilename = file };
config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
called via this:
```c#
var config_proxy = new ConfigurationProxy("my.dll.config");
config_proxy.InjectToConfigurationManager();
but with the same exception.
@joshfree Is this the same issue as dotnet/runtime#21246?
Assembly.GetEntryAssembly() is returning null - I'm hosting coreclr from unmanaged code in Linux.
@Cronan I'm not sure what the expectation is when hosting CoreCLR as to what Assembly.GetEntryAssembly() should return. @jkotas Do you have any idea on that part?
Were you trying to hit other statics on ConfigurationManager? When you're using OpenMappedExeConfiguration it doesn't impact the static entry points into ConfigurationManager. You'd want to get the AppSettings off of the Configuration object returned from the OpenMapped... method. That is, btw, the only real way to have consistency with custom locations on both desktop and core (desktop injection was done through AppDomain initialization, which we don't have in Core). Pulling from a static Configuration (or AppSettings) you control can also facilitate testing- in general it is the pattern I'd recommend.
If you can't even use the returned Configuration object I'd be interested in seeing the exact stack you get in that case.
When hosting CoreCLR, Assembly.GetEntryAssembly() will return the assembly that coreclr_execute_assembly was called on. It will return null if coreclr_execute_assembly was not called.
https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getentryassembly?view=netcore-2.0#remarks talks about this.
@jkotas @JeremyKuhne I think Assembly.GetEntryAssembly() is behaving correctly, given the circumstances, but my expectation is that I'm still able to use ConfigurationManager, even when called from unmanaged code, especially when providing the full path to the .config file.
In my code I'm just calling OpenExeConfiguration or OpenMappedExeConfiguration, not using other statics. The returned Configuration throws any time you touch anything that needs to call PrepareConfigSystem, e.g. GetSection(sectionName);
We should consider a fix here, or at least don't throw in the case we cannot locate a config file when run from a host.
@eerhardt any chance you could take a look at this one also? it is blocking an investigation that @AArnott is performing. He's targeting Windows though.
Looking. I'll let you know what I find out.
Most helpful comment
Looking. I'll let you know what I find out.