Click here to Skip to main content
15,891,006 members
Articles / Programming Languages / C#
Article

App.Config for your DLL

Rate me:
Please Sign up or sign in to vote.
3.56/5 (17 votes)
11 Nov 2005Public Domain3 min read 288.8K   50   37
Using an app.config in your DLL.

Introduction

When developing DLLs for distribution, it is often desired to have an app.config file associated with that DLL. However, the .NET 1.1 Framework only allows a single app.config and it is usually associated with the running application. This really leaves developers in a pinch as they do not know if an application is using an app.config to "merge" its entries into, or they require the application developer to include entries into their config file for DLL usage.

Background

One method commonly used is to write your own XML file and put your configuration info there. This method has several drawbacks. What if you have included a third party DLL that has configuration information that it expects to see in an app.config file? You are now stuck with the same problem. One such case of this problem arises when you use the Microsoft Enterprise Library in your DLL. The Libraries configuration tool adds a line into the app.config file that points to its own config file for internal use. When you call a library class, it looks in the app.config file for the name of its own config file. Things get ugly from here.

If you have attempted to Google an answer to this problem, you will find "can't be done". This article will explain how it can be done.

I want to start by stating the following disclaimer(s): It is not a normal practice to use reflection to "patch" back another class. This example is an extreme case to get around what I consider is a serious flaw in the .NET Framework. Portability was not a factor when developing this technique. This technique is not needed with .NET 2.0 in my understanding. All that said, let's get started.

Using the code

The .NET Framework reads the application configuration file into a static hashtable whenever the application domain is first referenced. Once it is read, it cannot be reread or modified. This is unfortunate as it does not allow us to call any methods or properties to alter this behavior. Not accepting that there is no workaround, I started to snoop into the .NET Framework System.Dll file using Lutz Roeder's .NET Reflector. What I found is that you can make the framework reread the config file if you reset its internal variables into thinking that the app.config file has not been read. Doing this is ugly, but desperate people take desperate measures.

The following code is a simple class to demonstrate how to do this. I will leave it up to the reader to put this in your own code.

The main point of all this is to change the ConfigurationSettings class static variable "_configurationInitialized" to false, and null out the "_configSystem". Doing so will make the framework read the app.config file into memory. It is very important to undo the changes made before you leave. If not, the using application will now be pointing at your DLL's config file. One method to ensure this safety is to wrap your config parameters into a class. I have added a static ConnectionString method to this class for demonstration purposes. It uses the C# "using" statement to make sure that our object is destroyed, and that "Dispose" is called to undo our changes. You can wrap calls to the Enterprise Library, or another third party DLL the same way.

C#
internal class MyDllConfig : IDisposable
{
    private string _oldConfig;
    private bool _libCompat;
    private const string _newConfig = "mydll.dll.config";
    // don't forget to rename this!!

    internal MyDllConfig()
    {
        _libCompat = Assembly.GetAssembly(typeof(
          ConfigurationSettings)).GetName().Version.ToString().
          CompareTo("1.0.5000.0") == 0;
        _oldConfig = AppDomain.CurrentDomain.GetData(
               "APP_CONFIG_FILE").ToString();
        Switch(_newConfig);
    }
    protected void Switch(string config)
    {    
        if ( _libCompat )
        {
            AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE",config);
            FieldInfo fiInit = typeof(
                System.Configuration.ConfigurationSettings).GetField(
                    "_configurationInitialized",
                    BindingFlags.NonPublic|BindingFlags.Static);
            FieldInfo fiSystem = typeof(
                System.Configuration.ConfigurationSettings).GetField(
                    "_configSystem",BindingFlags.NonPublic|BindingFlags.Static);
            if ( fiInit != null && fiSystem != null )
            {
                fiInit.SetValue(null,false);
                fiSystem.SetValue(null,null);
            }
        }
    }

    public void Dispose()
    {
        Switch(_oldConfig);
    }

    public static string ConnectionString()
    {
        string cstr;
        using ( new MyDllConfig() )
        {
            cstr = ConfigurationSettings.AppSettings["ConnectionString"];
        }
        return cstr;
    }
}

Points of Interest

I have place a small sanity check into this class that checks the version number of the System DLL that this was written for. If another version is detected, this patch is bypassed.

The AppDomain has a property SetupInformation that has a ConfigurationFile property. I found that if you set your app's config file name using this property then it is ignored. Using the SetData method causes the class to re-initialize this variable and gives us our desired results, including adding the application path onto our filename for us!

The Visual Studio IDE will allow you to place a generic app.config file into your DLL project. Adding the following line to your post build events will copy and rename this file to the appropriate place.

Copy $(ProjectDir)app.config $(TargetPath).config

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Web Developer
United States United States
Been involved in computer hardware and software since 1977. Experience includes Windows, Unix and embedded realtime systems. I own a software development company and have been CTO and Lead Engineer for both small and large companies.

Comments and Discussions

 
Questionusing Microsoft Enterprose LIb 2008 Pin
mail.roop@gmail.com29-Apr-12 20:50
mail.roop@gmail.com29-Apr-12 20:50 
QuestionLost config settings Pin
IT Re11-Oct-11 23:07
IT Re11-Oct-11 23:07 
GeneralAnother solution Pin
Pablo Romano17-Jul-09 9:43
Pablo Romano17-Jul-09 9:43 
GeneralRe: Another solution Pin
n10sive17-Jul-09 10:15
n10sive17-Jul-09 10:15 
GeneralRe: Another solution Pin
Pablo Romano17-Jul-09 10:58
Pablo Romano17-Jul-09 10:58 
GeneralAnother way might be.... [modified] Pin
mlohan10-Mar-09 9:53
mlohan10-Mar-09 9:53 
QuestionDoes it work in concurrency environment? Pin
Alexeins6-Feb-09 10:18
Alexeins6-Feb-09 10:18 
GeneralTranslate to VB.NET Pin
Booster01106-Feb-09 6:01
Booster01106-Feb-09 6:01 
GeneralRe: Translate to VB.NET Pin
Yeurl_200729-Jun-10 1:20
Yeurl_200729-Jun-10 1:20 
I know it s late, but for people who are interess


ps: i have done some modification for my proper use

enjoy

Imports System.Configuration<br />
Imports System.Reflection<br />
<br />
<br />
Friend Class MyDllConfig<br />
    Implements IDisposable<br />
    Private _oldConfig As String<br />
    Private _libCompat As Boolean<br />
    'Private Const _newConfig As String = "mydll.dll.config"<br />
    Private Shared _newConfig As String<br />
<br />
    Public Shared Property newConfig() As String<br />
        Get<br />
            Return _newConfig<br />
        End Get<br />
        Set(ByVal value As String)<br />
            _newConfig = value<br />
        End Set<br />
    End Property<br />
<br />
<br />
    ' don't forget to rename this!!<br />
    Protected Overrides Sub Finalize()<br />
        Dispose()<br />
    End Sub<br />
<br />
    Public Sub Dispose() Implements System.IDisposable.Dispose<br />
        Switch(_oldConfig)<br />
    End Sub<br />
<br />
<br />
    Friend Sub New()<br />
        _libCompat = Assembly.GetAssembly(GetType(ConfigurationSettings)).GetName().Version.ToString().CompareTo("1.0.5000.0") = 1<br />
        _oldConfig = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString()<br />
        Switch(_newConfig)<br />
    End Sub<br />
<br />
    Friend Sub New(ByVal a As String)<br />
        newConfig = a<br />
        _libCompat = Assembly.GetAssembly(GetType(ConfigurationSettings)).GetName().Version.ToString().CompareTo("1.0.5000.0") = 1<br />
        _oldConfig = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString()<br />
        Switch(_newConfig)<br />
    End Sub<br />
    Protected Sub Switch(ByVal config As String)<br />
        If _libCompat Then<br />
            AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", config)<br />
            Dim fiInit As FieldInfo = GetType(System.Configuration.ConfigurationSettings).GetField("_configurationInitialized", BindingFlags.NonPublic Or BindingFlags.[Static])<br />
            Dim fiSystem As FieldInfo = GetType(System.Configuration.ConfigurationSettings).GetField("_configSystem", BindingFlags.NonPublic Or BindingFlags.[Static])<br />
            If fiInit IsNot Nothing AndAlso fiSystem IsNot Nothing Then<br />
                fiInit.SetValue(Nothing, False)<br />
                fiSystem.SetValue(Nothing, Nothing)<br />
            End If<br />
        End If<br />
    End Sub<br />
<br />
<br />
<br />
    Public Shared Function ConnectionString() As String<br />
        Dim [cstr] As String<br />
        Using New MyDllConfig()<br />
            '[cstr] = ConfigurationSettings.AppSettings("ConnectionString")<br />
            [cstr] = ConfigurationManager.ConnectionStrings("DBConnectionStringForMysqlToDom").ToString() '  AppSettings("ConnectionString").<br />
        End Using<br />
        Return [cstr]<br />
    End Function<br />
<br />
<br />
End Class<br />

General.NET 1.1 Security Update breaks this work around Pin
Daniel Fowler11-Jul-07 0:40
Daniel Fowler11-Jul-07 0:40 
GeneralRe: .NET 1.1 Security Update breaks this work around Pin
Member 4465776-Dec-07 2:02
Member 4465776-Dec-07 2:02 
GeneralBetter solution for EnterpriseLibrary in NET 2.0 Pin
Ann Jose17-Mar-07 23:06
Ann Jose17-Mar-07 23:06 
GeneralVB6 calling a .net 2 dll Pin
s10iyer19-Sep-06 22:49
s10iyer19-Sep-06 22:49 
GeneralRe: VB6 calling a .net 2 dll Pin
n10sive20-Sep-06 5:04
n10sive20-Sep-06 5:04 
QuestionRe: VB6 calling a .net 2 dll Pin
DylanWind27-Nov-08 21:26
DylanWind27-Nov-08 21:26 
QuestionDll resides in the GAC Pin
Xavi23cr28-Jun-06 14:52
Xavi23cr28-Jun-06 14:52 
General.NET Framework 2.0 Pin
Rishi K. Kapoor28-Jun-06 11:18
Rishi K. Kapoor28-Jun-06 11:18 
AnswerRe: .NET Framework 2.0 Pin
Nguyen20092-Jun-08 5:54
Nguyen20092-Jun-08 5:54 
GeneralThis does not work on 2003 Server with SP1 Pin
Bjørn E.9-Jun-06 4:13
Bjørn E.9-Jun-06 4:13 
GeneralRe: This does not work on 2003 Server with SP1 Pin
n10sive9-Jun-06 5:03
n10sive9-Jun-06 5:03 
GeneralRe: This does not work on 2003 Server with SP1 Pin
Ed Rakovsky7-Mar-07 10:44
Ed Rakovsky7-Mar-07 10:44 
GeneralRe: This does not work on 2003 Server with SP1 Pin
mcerutti28-Mar-07 2:20
mcerutti28-Mar-07 2:20 
GeneralFramework .NET 2.0 Pin
Carloni21-Feb-06 7:54
Carloni21-Feb-06 7:54 
GeneralRe: Framework .NET 2.0 Pin
n10sive21-Feb-06 9:34
n10sive21-Feb-06 9:34 
NewsRe: Framework .NET 2.0 Pin
Mazhekin7-May-06 4:35
Mazhekin7-May-06 4:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.