Wednesday, February 13, 2008

App.config in C# with VS2005 - Part II: DLL within an EXE

In part I I looked at using the app.config from an EXE. In part II I'm going to look at using app.config from a DLL that is called by an EXE.

So, create a DLL project (mine is called "TestAppConfigDll") and add it to your EXE project. Use the Settings designer again to add your app.config file to your DLL (right-clicking on the project, selecting "properties" and then choosing the "settings" tab). I'm going to add an "Application" setting called "MyDllVal". Again we get a pretty similar looking app.config file in our project:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section
name="TestAppConfigDll.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<TestAppConfigDll.Properties.Settings>
<setting name="MyDllVal" serializeAs="String">
<value>18.2</value>
</setting>
</TestAppConfigDll.Properties.Settings>
</applicationSettings>
</configuration>


And again, we can access the value in code using:

string myDllVal = 
TestAppConfigDll.Properties.Settings.Default.MyDllVal;


No surprise to find that the config file in our bin folder (..\TestAppConfigDll\bin\Debug) is prefixed by the dll name, "TestAppConfigDll.dll.config" in my case. BUT looking in the bin for the EXE project (which references the dll and contains a copy of my dll file), there is no dll.config file, just the original exe.config. And the exe.config has no "MyDllVal" property. If I run the EXE it picks up the original value for "MyDllVal" but I have no way to modify it! It knows the original compile-time value because it has been hard-coded into the "Settings.Designer.cs" file that was generated when you entered your value via the Settings designer. Here is the code if you are interested (my original value was "18.2"):


[global::System.Configuration.
ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.
DebuggerNonUserCodeAttribute()]
[global::System.Configuration.
DefaultSettingValueAttribute("18.2")]
public string MyDllVal {
get {
return ((string)(this["MyDllVal"]));
}
}


So, what if I add a dll.config ("TestAppConfigDll.dll.config") under the EXE bin folder - will it read it on start-up? Nope - it doesn't read it.

So, maybe it is looking in the exe.config for my setting. What if I merge my "MyDllVal" setting into the exe.config file - will it read it on start-up? Wooeee! That works! So I had to take two chunks of xml from the dll.config to the exe.config; (i) the "section", and (ii) the "{dllname}.Properties.Settings". The resulting exe.config looks like this:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section
name="TestAppConfig.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
<section
name="TestAppConfigDll.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<TestAppConfig.Properties.Settings>
<setting name="MyVal" serializeAs="String">
<value>17</value>
</setting>
</TestAppConfig.Properties.Settings>
<TestAppConfigDll.Properties.Settings>
<setting name="MyDllVal" serializeAs="String">
<value>18.00 combo</value>
</setting>
</TestAppConfigDll.Properties.Settings>
</applicationSettings>
</configuration>


So the upshot is, if the DLL is called from an EXE, then the DLL will try to get its app.config settings from the EXE's app.config file. Even if I remove the EXE's app.config, the DLL does not use the DLL's app.config file.

Man, this is annoying! Why have they done it this way? Maybe it is so that shared DLLs in the GAC can have different config settings for different EXEs. But even then, couldn't they have used the EXE config settings first, and if none, then use the DLL config settings?

So where will it look for app.config if I have a .Net DLL in the GAC that is begin called from a VB6 exe via COM interop? Probably nowhere I guess.

The solution seems to be to use a custom config file for your DLL app settings. However my DLL is using a web-service and the .Net web service tool puts the web service URI into, you guessed it, the app.settings file for the DLL. I want access to the app.config so I can change the web service URI to point to a different web service. Again, I can get around it by setting the web service URI manually in the code, but I'm starting to fight the framework rather than use it!

10 comments:

t said...

Very nice article. It helped me understand the perils of configs and helped me think of a workaround to my issue. Thanks!

Jon Simmons said...

Any chance you came up with a workaround for this. I'm dealing with the same issue now, trying to set the WebService URL at run time from within a .dll

Jonts said...

I went away from using the .Net-created *.config files and created my own custom INI files. I search for my INI file in the current folder, and if not found (eg. for a GAC dll), then I check the Windows System folder. In the end I felt it was better for me to be in control of this data.

María Paz said...

Excellent Post.
I have similar problem, I have a dll project and web application.
I have a static class to initialize my NHibernate Framework using a path in dll application settings.

Thanks.

María Paz said...

Me again,
I found this post
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_frm/thread/173c2b36f3c679a4/e34b1675db9b4486?lnk=st&q=dotnet+applicationSettings+web.config+dll+properties&rnum=1&pli=1

Explain how to add dll.config into web.config.

Pablo Romano said...
This comment has been removed by the author.
Pablo Romano said...

I had the same problem, after struggling with it for some days I found a solution.

I wrote a post about it http://moebiusit.com/blog/pabloromano/2009/07/13/changing-dll-settings-without-re-compiling/

Hope it helps!

Tarek Siala said...

Very nice article, now i understand why i can't use app.config from my DLL project, i spend 2 days to do it, but after i read this post i know why, thanks

Fuhan said...

Sometimes you might just not look into the right place. As a matter of fact, the ConfigurationManager.OpenExeConfiguration can do the trick to load a dll config file, although it is called OpenExeConfiguration(). The following code works:

Configuration conf = System.Configuration.ConfigurationManager.OpenExeConfiguration(dllFileName);
string testSettingName = conf.AppSettings.Settings["TestSettingName"].Value;

There is one trick though. When a dll is compiled, the app.config in the dll project gets copied to the output folder and named as DllName.dll.Config. This file does not get copied automatically to the referencing exe output folder when the exe is built. As long as DllName.dll.Config is in the exe folder, the above code would work like a charm.

Naeem Akram said...

Thank you boss,

Your post was very helpful. I'm creating a couple of libraries with dlls, was baffled to see no .config.dll files alongside .config.exe :p