views:

63

answers:

2

We have a Visual Studio 2010 solution that contains several C# projects in accordance with Jeffery Palermo's Onion Architecture pattern (http://jeffreypalermo.com/blog/the-onion-architecture-part-1/). We have a UI project that is an ASP.Net MVC project, and we have a C# Class Library project called Infrastructure that is referenced by the UI project. In our Infrastructure project we have added an app.config file to contain settings that are specific to the Infrastructure project. At runtime, the app.config file doesn't appear to be available to the Infrastructure project, only the web.config file contained in the UI project. We don't want to put settings that pertain to the Infrastructure project into the web.config file in the UI project, the UI has no need for those settings. How can we make the Infrastructure's app.config file available at runtime? We were thinking maybe we should put a Post Build Copy to copy the app.config out to the UI directory when the application is built - is that the right way to do this, or is there a better way?

+1  A: 

Even if you post-build-copy the app.config it will not solve your problem. The application is still a web app, so the config system will use the web.config file. The settings will need to go in there one way or another. One way to still keep those settings a bit separate is to put them into a custom config section, and then put the settings for this section into a separate file. It will still need to be referenced from the web.config though (using a configSource attribute).

Fredrik Mörk
A: 

Generally, you'll be told that this can't be done. However, you can certainly load a config file using the System.Configuration.ConfigurationManager.OpenExeConfiguration method. You can pass in the file path to your assembly (it doesn't have to be an executable, despite the method name).

Granted, this doesn't merge your assembly's config settings into the executing application's config settings, and I don't think that it should. Your assembly just has to know that it needs to retrieve its settings through a different mechanism than the System.Configuration.ConfigurationManager.GetSection function or the static AppSettings property on that class.

Below is a very simple example for a "Settings" class that loads a .config file for the assembly of which it is a part.

public static class Settings
{
    public static System.Configuration.Configuration Configuration { get; private set; }

    static Settings()
    {
        // load a .config file for this assembly
        var assembly = typeof(Settings).Assembly;
        Configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(assembly.Location);

        if (Configuration == null)
            throw new System.Configuration.ConfigurationErrorsException(string.Format("Unable to load application configuration file for the assembly {0} at location {1}.", assembly.FullName, assembly.Location));
    }

    // This function is only provided to simplify access to appSettings in the config file, similar to the static System.Configuration.ConfigurationManager.AppSettings property
    public static string GetAppSettingValue(string key)
    {
        // attempt to retrieve an appSetting value from this assembly's config file
        var setting = Configuration.AppSettings.Settings[key];
        if (setting != null)
            return setting.Value;
        else
            return null;
    }
}

And the usage...

public class UsageExample
{
    void Usage()
    {
        string mySetting = Settings.GetAppSettingValue("MySetting");

        var section = Settings.Configuration.GetSection("MySection");
    }
}

Now, you'll still have to work out build issues. Adding an "Application Configuration File" (App.config) item to your class library assembly does cause Visual Studio to copy it to that assembly's output folder as .dll.config, but it is not automatically copied to the output folder of any executable applications that reference that project. Therefore, you'd need to add a post-build step to copy the file to the appropriate location, as you mentioned.

I'd consider having a post-build step on the class library that copies the .config file out to a solution-level "Configurations" folder, then have a post-build step for executable projects to copy everything from the "Configurations" folder to the output folder. I'm not sure if that would actually work well, but if it does then you wouldn't be creating additional dependencies between projects in your post-build steps (that might make maintenance difficult).

EDIT: Ultimately, you should consider whether this is really what you want to be doing. It isn't the normal approach, and generally you might be better served by utilizing the other answer to this question that mentions using the configSource attribute.

Drawbacks to this approach that may not be obvious are that you won't be able to put settings for third-party components into your class library's config file and expect them to be used. For instance, if your class library is using log4net, you can't put log4net's settings in your class library's config file, because the log4net components still expect to load settings from the executable's config file.

Dr. Wily's Apprentice