I face one issue when I tried to get something for my app.config.
So my code is simple:
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap()
{
ExeConfigFilename = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
};
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
string value = config.AppSettings.Settings["test"].Value; // this is working
string value2 = System.Configuration.ConfigurationManager.AppSettings["test"]; // throw an exception
The only tricky stuff here is the way of my code is loaded.
An C++ exe load my C# Assembly in an AppDomain and call my code.
I have this kind of file structure
Application.exe (C++)
myDll.dll.config
myDll.dll
The problem is some library like NLog for example call ConfigurationManager.GetSection() and this block the init of the logger.
So do you have any idea arround this ?
Thanks in advance for your help ;)
Extra Info:
Net 4.7.2
Windows 10
Related
I need to create a "BadimageFormatException" in my local to test some cacheing issue. How to create "BadImageFormatException"?
As already specified in the comments, you can just create and throw this exception:
throw new BadImageFormatException();
If you want to cause this exception naturally, then as per MSDN documentation,
This exception is thrown when the file format of a dynamic link library (.dll file) or an executable (.exe file) doesn't conform to the format that the common language runtime expects
It means that you can cause it by trying to load an invalid assembly file:
string tempPath = Path.GetTempFileName();
using (var file = File.OpenWrite(tempPath))
using (var sw = new StreamWriter(file))
{
sw.WriteLine("I am not an assembly");
}
Assembly.LoadFile(tempPath);
Thanks to #Xiaoy312 for the advice. There is a much simpler way to do this using Assembly.Load:
Assembly.Load(new byte[] { 0 });
If new to this, then one way also is to load an unmanaged assembly for example notepad.exe.
try
{
// path to notepad.exe.
string path = Environment.ExpandEnvironmentVariables("%windir%") + #"\System32\notepad.exe";
Assembly assembly = Assembly.LoadFile(path);
}
catch (System.BadImageFormatException exception)
{
// catch an exception.
}
As Notepad is unmanaged and not compiled with .Net, .net isnt very happy and throws the exception.
For interesting trivia, BadImageFormatException has nothing to do with bad image format like gifs or jpegs but its an exception when .Net attempts to load a DLL or exe which isnt compatible with CLR.
Also, all exceptions are derived from System.Exception. BadImageFormatException is just inherited from System.Exception.
Consider the following:
A windows service with a config file and the setting Engine.Url
The service loads an assembly into its own AppDomain
Code in the the assembly needs the setting Engine.Url
string s = ConfigurationManager.AppSettings["Engine.Url"]
does not work, s will be null.
Then I tried
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
string engineUrl = config.AppSettings["Engine.Url"];
this doesnt compile with the error:
'System.Configuration.ConfigurationElement.this[System.Configuration.ConfigurationProperty]' is inaccessible due to its protection level
Is there any way to get to the standard config file from within an AppDomain?
edit:
This doesn't work either, engineUrl will be null:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
KeyValueConfigurationElement engineUrl = config.AppSettings.Settings["Engine.Url"];
Simple answer: Yes, but it's wonky.
You have a couple options. You can set, I believe, the ConfigurationFile property of an AppDomainSetup object used when creating your AppDomain.
You can call AppDomain.SetData("APP_CONFIG_FILE", path_to_file) (see the related MSDN page)
In my Application I use Common.Logging library in order to abstract logging functionality. In startup assembly it was configured (in app.config file) to work against Log4Net library. There are established some Appenders: ConsoleAppender, RollingFileAppender, TraceAppender. Everything works fine in the single AppDomain. However I have found that logging does not work in the newly created AppDomain. i.e:
Logger.Info( "Logging works here" ); // Logging works here
var appDomain = AppDomain.CreateDomain(
"AppDomain." + componentHost.FullName,
AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.SetupInformation );
var proxy = (IComponentHost) appDomain.CreateInstanceAndUnwrap(
componentHost.Assembly.FullName,
componentHost.FullName,
false,
BindingFlags.Default,
null,
new object[] { },
null,
null );
proxy.Init(); // Logging does not work in Init() method stack
I'm trying to find a solution, both using app.config configuration as well as Common.Logging API (i.e LogManager.Reset() method), but it doesn't solve a problem.
How can I force Common.Logging / Log4Net to work properly in newly created AppDomain? Please for help.
I have a similar issue with log4net. I used XmlConfigurator.Configure() without parameters that uses Assembly.GetCallingAssembly() to get configuration file. I replaced it with:
var configFile = new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
if (!configFile.Exists)
throw new Exception($"Failed to find configuration file '{configFile.FullName}'");
XmlConfigurator.Configure(configFile);
From the code you show, it looks like you're not providing a configuration file for your app domain. It's been a few years since I've done this, but if I recall correctly, the configuration file for a new app domain is empty by default.
Here's an example of how to use the AppDomainSetup class:
AppDomainSetup ads = new AppDomainSetup();
ads.SetConfigurationBytes( Encoding.UTF8.GetBytes(
#"<configuration>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.3.5"></remove>
</DbProviderFactories>
</configuration>" ) );
(Credit to Tom Overton for the code sample.)
See http://social.msdn.microsoft.com/Forums/vstudio/en-US/a23ff0ad-8a4c-4aaf-8281-dcc7e840f8a5/assigning-appconfig-to-appdomain?forum=clr for his explanation of this issue.
I wrote a custom build task that reads values form the appsettings in it's App.config file. When I compile my task as an executable and run it, the task works perfectly. The correct values are read from the config file. However when I compile it as an assembly and run it from a target in my build script I get a System.NullReferenceException. The exception occurs in the foreach loop because the configuration manager returns null.
IEnumerable<string> tables = ConfigurationManager.AppSettings.GetValues(key);
foreach (string txt in tables)
{
Logic.....
}
I'm calling the custom task correctly because I commented out the issue and it builds successfully.
Does anyone know why this might be happening? or if I'm even able to use a App.config file with custom build tasks?
Thanks in advance
If you compile a project as a library, then it reads from the app.config of the calling executable. If you compile a project as an executable, then it reads from it's own app.config.
If anyone is interested I used the following code to access the custom config
private static string[] GetConfigFile()
{
var map = new ExeConfigurationFileMap();
map.ExeConfigFilename = #"C:\ConfigFile.config";
config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
return config.AppSettings.Settings.AllKeys;
}
The above code gets the list of keys from the specified config file.
The return value is stored in a string array which I run through using a foreach loop as seen below
string[] keyNames = GetConfigFile();
foreach (string keys in keyNames )
{
KeyValueConfigurationElement keyval = config.AppSettings.Settings[keys];
Console.WriteLine(keyval.Value);
}
When i am using a web application, the line of code below
Configuration objConfig =
ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None);
in class library are giving this error:
"exePath must be specified when not running inside a stand alone exe."
Previously a console application was being used, and the code could access the app.config. I tried using the System.Web.Configuration in class library but the dll was not present in the .Net tab for "Add reference".
Kindly help :)
You need to use a different configuration manager in a web context. The following code
block shows an example of how to deal with this:
System.Configuration.Configuration configuration = null;
if (System.Web.HttpContext.Current != null)
{
configuration =
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
}
else
{
configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
}
I'm not sure what you're doing; but at first glance it looks like you're trying to use code written for a WinForms application in a web environment. This almost certainly will not work, since your web app won't have the permissions you need.
Try looking up how to do this in a web environment (since you seem to be dealing with config files, try searching on WEB.CONFIG to start)
I tried to use the answer from #shane but ended up with the same exception using Hangfire. This code worked for me though:
System.Configuration.Configuration configFile = null;
if (System.Web.HttpContext.Current != null)
{
configFile =
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
}
else
{
System.Configuration.ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = $"{System.AppDomain.CurrentDomain.BaseDirectory}Web.Config" };
configFile = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
}
Note that editing Web.config will cause the application pool to restart!