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.
Related
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
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)
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!
I have a DLL (library project in vs2008), that calls to external web service. Project has a Service reference to external webservice
I have Unit test, and app.config (with servicemodel configuration) in unit test project, and all is right.
Now, I use Addin VS 2008, and has'nt configuration file like Windows Forms or Asp.net.
the addin is a dll and it has config file.
If I use WCF (using my project DLL), the config system.servicemodel not found
I have seen this:
http://vassiltonev.blogspot.com/2009/03/loading-custom-config-file-instead-of.html
but Adding a custom wcf behavior extension causes a ConfigurationErrorsException
The type 'Microsoft.ServiceModel.Samples.CustomTextMessageEncodingElement, CalidadCodigo.Integracion.CustomTextEncoder' registered for extension 'customTextMessageEncoding' could not be loaded. (E:\TFS\pro\AddIn\bin\Debug\MyAddIn.dll.config line 123
I test with Assembly QualifiedName in my extensions WCF but wrong.
any more suggestions or any sample code ?
my config
<extensions>
<bindingElementExtensions>
<add name="customTextMessageEncoding"
type="Microsoft.ServiceModel.Samples.CustomTextMessageEncodingElement,CalidadCodigo.Integracion.CustomTextEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
The code
internal static WebServicePortTypeClient CrearClienteWCF()
{
try
{
return new WebServicePortTypeClient();
}
catch (Exception ex)
{
//TODO: not found serviceModel config
var addInConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);
var endpointAddress = addInConfig.AppSettings.Settings[EasyVistaSvcEndPointAddress].Value;
var endpoint = new System.ServiceModel.EndpointAddress(endpointAddress);
return new WebServicePortTypeClient(EndPointConfigurationName, endpoint);
// The type 'Microsoft.ServiceModel.Samples.CustomTextMessageEncodingElement, CalidadCodigo.Integracion.CustomTextEncoder' registered for extension 'customTextMessageEncoding' could not be loaded. (E:\TFS\pro\AddIn\bin\Debug\MyAddIn.dll.config line 123)
}
}
AFAIK its not possible to use the ConfigurationManager in a DLL. I ran in the same issue while I wrote a Plugin for VS2010.
My Solution was to load the settings from a file an create the endpoint and endpointadress by myself in the code like this:
Uri myUri = loadUriFromFile();
var endpoint = new EndpointAddress(myUri);
NetTcpBinding binding = GetNewTcpBindingFromFile();
return new WebServicePortTypeClient(binding, endpoint);
I am looking to redirect the standard .Net ConfigurationManager class to another file; entirely. The path is determined at runtime so I can't use configSource or such (this is not a duplicate question - I have looked at the others).
I am essentially trying to duplicate what ASP.Net is doing behind the covers. Thus not only my classes should read from the new config file, but also any standard .Net stuff (the one I am specifically trying to get to work is the system.codeDom element).
I have cracked open Reflector and started looking at how ASP.Net does it - it's pretty hairy and completely undocumented. I was hoping someone else has reverse-engineered the process. Not necessarily looking for a complete solution (would be nice) but merely documentation.
I finally figured it out. There is a public documented means to do this - but it's hidden away in the depths of the .Net framework. Changing your own config file requires reflection (to do no more than refresh the ConfigurationManager); but it is possible to alter the configuration file of an AppDomain that you create via public APIs.
No thanks to the Microsoft Connect feature I submitted, here is the code:
class Program
{
static void Main(string[] args)
{
// Setup information for the new appdomain.
AppDomainSetup setup = new AppDomainSetup();
setup.ConfigurationFile = "C:\\my.config";
// Create the new appdomain with the new config.
AppDomain d2 = AppDomain.CreateDomain("customDomain", AppDomain.CurrentDomain.Evidence, setup);
// Call the write config method in that appdomain.
CrossAppDomainDelegate del = new CrossAppDomainDelegate(WriteConfig);
d2.DoCallBack(del);
// Call the write config in our appdomain.
WriteConfig();
Console.ReadLine();
}
static void WriteConfig()
{
// Get our config file.
Configuration c = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Write it out.
Console.WriteLine("{0}: {1}", AppDomain.CurrentDomain.FriendlyName, c.FilePath);
}
}
Output:
customDomain: C:\my.config
InternalConfigTest.vshost.exe: D:\Profile\...\InternalConfigTest.vshost.exe.config