Xaqron
Xaqron

Reputation: 30857

If an ASP.NET application uses many DLLs, what's the best approach for keeping configurations of each dll separate?

After creating settings for each dll, a .dll.config file is generated. If that dll be part of an asp.net application, how to keep this configurations separate for each dll and don't merge them into web.config ?

Example: I have a GMailSender class library (DLL) which sends email via GMail servers. All you need is an instance of GMailSender, like this:

GMailSender gms = new GMailSender();
gms.To = "[email protected]";
gms.Subject = "System.Configuration dilemma";
gms.Body = "Can anyone help me with this question ?";
gms.Send();

Consider GMailSender is inside GMailSender.dll and it's configuration file is GMailSender.dll.config and the username and password of GMail account are inside it.

I want this DLL use the config file of itself (both dll and config in the same directory, i.e in Bin folder of an ASP.NET application) or beside a desktop application. This way the GMailSender is independent of who is using him for retrieving it's configurations (current AppDomain who has loaded this DLL).

I want this without reconstructing the wheel (no custom configuration classes). I guess its possible with System.Configuration but this namespace is probably the worst designed of .NET !

Please don't tell why you designed so that ...

This is a plug-in based design and finally MEF do some kind of it now in .NET 4.0, but there's the same problem for Parts configurations. With MEF at least I don't need anymore to argue for plugin-based design advantages.

Upvotes: 3

Views: 1026

Answers (5)

Florin Dumitrescu
Florin Dumitrescu

Reputation: 8282

What you need can be achieved using Custom Configuration Sections. This MSDN article provides some details and samples on how to implement such config sections.

If you need simple key/value configs, like in the appSettings section, then creating a custom configuration section is quite simple.

The first thing you need to do is define your config section inside web.config:

<configSections>
  <section name="GmailSettings" restartOnExternalChanges="true" type="System.Configuration.NameValueFileSectionHandler" />
</configSections>

Now inside the web.config file you can declare the GmailSettings section and set the location of the external config file that you are going to use for that setting:

<GmailSettings configSource="GmailSettings.config"></GmailSettings>

configSource specifies the name and location of the external config file used for defining the GmailSettings section. Please note the restartOnExternalChanges attribute used when defining the section. Set it to true if you want the application to be automatically restarted when you modify the GmailSettings.config file (as it does when you modify the web.config file).

Below is an example of how to implement the GmailSettings.config file:

<?xml version="1.0"?>
<GmailSettings>
  <add key="userName" value="blabla"/>
  <add key="password" value="moreBla"/>
</GmailSettings>

You can access the settings from GmailSettings using the ConfigurationManager.GetSection() method or by implementing a helper class like the one below:

public class GmailSettings
{
    private static readonly GmailSettings _instance = new GmailSettings();
    private NameValueCollection _settings = ConfigurationManager.GetSection("GmailSettings") as NameValueCollection;

    public static GmailSettings Instance
    {
        get { return _instance; }
    }

    public string this[string key]
    {
        get { return _settings[key]; }
    }
}

The settings can now be accessed like GmailSettings.Instance["userName"].

Hope this helps.

Upvotes: 4

Yossarian
Yossarian

Reputation:

What you are looking for cannot be done out of the box. Also, ASP.NET do a shadow copy on DLLs so writing a custom configuration class is not easy to. Your DLLs are not run from Bin folder. THey run from appDomainSetup.CachePath so the *.dll.config files are not beside their assemblies at run-time.

You can add a refrence to *.dll.config files inside web.config instead of copy/paste all key/values from DLL configuration files into web.config; This is possible by using File element in web.config.

I think this is not intended by designers in past and composition became popular in recent years.

Upvotes: 1

Mark Redman
Mark Redman

Reputation: 24515

I would add configuration settings to the web.config file and call:

ConfigurationManager.AppSettings["DllName.MySetting"]

This means all configuration settings are in one place and not in the Bin folder.

Upvotes: 0

Nicholas Carey
Nicholas Carey

Reputation: 74277

To do what I believe you want to do -- give your DLL a configuration file about which referencing assemblies need no nothing, you can[1] do something like the following code.

static class DllConfigurationFactory
{
    public static Configuration GetConfigurationInstance()
    {
        string           callingAssemblyPath = Assembly.GetCallingAssembly().Location ;
        string           configFilePath      = string.Concat( callingAssemblyPath , ".config" ) ;

        // getAttributes hurls with a multitude of exceptions
        FileAttributes   attributes  = File.GetAttributes( configFilePath ) ;
        bool             isDirectory = ( (attributes&FileAttributes.Directory) == FileAttributes.Directory ? true : false ) ;
        if ( isDirectory )
        {
            throw new FileNotFoundException() ;
        }

        // check for (and die with an SecurityException) if we dont' have read access
        new FileIOPermission( FileIOPermissionAccess.Read , configFilePath ).Demand() ;

        ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
        configMap.ExeConfigFilename = configFilePath ;
        Configuration instance = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
        return instance ;
    }

}

This factory method does the following:

  1. Finds the fully-qualified path of the assembly of the caller ((not that of the assembly containing the factory -- it, after all, might be in its own DLL).

  2. Tacks a ".config" on to the end of that path (thus yielding something like 'C:\usr/bin/local/foo/myAssembly.dll.config'.

  3. Ensures that that file exists and is readable, throwing an appropriate exception if not.

  4. Using that path as the source, instantiates a new instance of System.Configuration.Configuration and returns it to the caller.

Notes

  • Visual Studio will take an app.config in your DLL project and turn it into a foo.dll.config file, but your build/deploy/install system is responsible for copying it to the correct location(s). Visual Studio will put it in the bin directory for the DLL project, but it won't get copied any further up the line.
  • You may need to do some experimenting -- you might need to include appropriate entries in the element, even for "standard" sections, since you're outside the normal config file hierarchy. I'm not sure on this, though. In my test, it found and loaded the element without a element defined, so you might have full access to the user and machine config files as well, but I don't make any guarantees about that. YMMV and all that.

Good Luck!

[1] TMTOWTDI as they say in Perl (There's more than one way to do it). You could also, for instance, create a custom section and park it in machine.config.

And there's no requirement that you use the .Net configuration system for this: your factory method could slurp in any arbitrary XML and deserialize it into an object of your choice. This would give you a strongly typed, bound access to the configuration properties, albeit at the expense of automatic refreshing when the config file gets changed. Although...you could also just put a wrapper around the standard Configuration object that would provide the same thing.

Upvotes: 1

usr-local-ΕΨΗΕΛΩΝ
usr-local-ΕΨΗΕΛΩΝ

Reputation: 26874

Creating an App.config for a DLL is not a good practice. Configuration belongs to the running application. The class library dll is supposed only to provide services to the calling application.

HOWEVER

If you wrote the DLLs on your own, then you can make these DLL's code prefer their own independent .dll.config file rather than the global App.config/Web.config (in your ASP.NET case) using a trick.

This method allows you to open any executable file's .config file, but no one prevents you from calling it with "Mydll.dll" as argument, and has the same effect. But this works only if you can access these DLL's code.

A good practice is to use configuration sections, which are easy to maintain when merged inside a single configuration file.

Upvotes: 1

Related Questions