I recently wrote a library that contained some configuration class code that used the System.Configuration namespace. Along with the code, I provided a facade class to facilitate loading of the config. One thing I couldn't know when the library was consumed was whether it was consumed by an ASP.net project or a Windows project.

Though it feels clunky to me and prone to breaking sometime in the future, I ended up up checking by comparing against known ASP.net host process names.

public static bool IsAspNetHostProcess()
{
    var iisProcessNames = new[] {
      "iisexpress", 
      "w3wp", 
      "aspnet_wp"
      };

    var processName = Process.GetCurrentProcess().ProcessName;
    var isAspNet = iisProcessNames.Any(x => x == processName);
    return isAspNet;
}

And then I proceeded to load the configuration with the calls provided by the appropriate ConfigurationManager class.

public static System.Configuration.Configuration GetHostProcessConfiguration()
{
    var configuration = IsAspNetHostProcess() ? 
        WebConfigurationManager.OpenWebConfiguration("~") :
        ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    return configuration;
}

After I had done this, the consuming code could call my facade class and get a proper instance of my custom ConfigurationSection. However, I did run into one particularly nasty issue, and it had to do with using the WebConfigurationManager.OpenWebConfiguration method call. I had written unit tests against the code above (which obviously only tested the 'non-ASP.net process' path) and it passed with flying colors. It wasn't until I used this code in my ASP.net project that I experienced extreme frustration (?!?). Originally, I had called WebConfigurationManager like so:

WebConfigurationManager.OpenWebConfiguration("~/web.config")

Do not, I repeat, do not do this. For some unconceivable reason, in my case, it did return an instance of my custom ConfigurationSection class, but some of the values on the properties decorated with ConfigurationPropertyAttribute were set to their defaults at some point in the loading. I could tell it didn't happen immediately when loading, as while stepping through the code I could see the proper values populating the properties. For some reason unbeknownst to me, at some point in the loading they were replaced with defaults.

I can't even reason about why this would happen. Anyways, changing the path parameter to simply "~" fixed the whole issue.