views:

2977

answers:

5

I really want to be able to have a way to take an app that currently gets its settings using ConfigurationManager.AppSettings["mysettingkey"] to actually have those settings come from a centralized database instead of the app.config file. I can make a custom config section for handling this sort of thing, but I really don't want other developers on my team to have to change their code to use my new DbConfiguration custom section. I just want them to be able to call AppSettings the way they always have but have it be loaded from a central database.

Any ideas?

A: 

I'm not sure you can override it, but you can try the Add method of AppSettings to add your DB settings when the applications starts.

Santiago Palladino
A: 

Whatever you do you will need to add one layer of redirection? ConfigurationManager.AppSettings["key"] will always look in the configuration file. You can make a ConfigurationFromDatabaseManager but this will result in using different calling syntax:

ConfigurationFromDatabaseManager.AppSettings["key"] instead of ConfigurationSettings["key"].
azamsharp
i think the reason for the question is the need to override the existing usage that is all over the code to remove the need for extensive code base changes. could be wrong though.
John Nicholas
A: 

It appears there is a way to do this in .NET 3.5 by setting the allowOverride attribute in the appSettings definition section of machine.config. This allows you to override the entire section in your own app.config file and specify a new type to handle it.

skb
+6  A: 

If you don't mind hacking around the framework and you can reasonably assume the .net framework version the application is running on (i.e. it's a web application or an intranet application) then you could try something like this:

using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Internal;
using System.Reflection;

static class ConfigOverrideTest
{
  sealed class ConfigProxy:IInternalConfigSystem
  {
    readonly IInternalConfigSystem baseconf;

    public ConfigProxy(IInternalConfigSystem baseconf)
    {
      this.baseconf = baseconf;
    }

    object appsettings;
    public object GetSection(string configKey)
    {
      if(configKey == "appSettings" && this.appsettings != null) return this.appsettings;
      object o = baseconf.GetSection(configKey);
      if(configKey == "appSettings" && o is NameValueCollection)
      {
        // create a new collection because the underlying collection is read-only
        var cfg = new NameValueCollection((NameValueCollection)o);
        // add or replace your settings
        cfg["test"] = "Hello world";
        o = this.appsettings = cfg;
      }
      return o;
    }

    public void RefreshConfig(string sectionName)
    {
      if(sectionName == "appSettings") appsettings = null;
      baseconf.RefreshConfig(sectionName);
    }

    public bool SupportsUserConfig
    {
      get { return baseconf.SupportsUserConfig; }
    }
  }

  static void Main()
  {
    // initialize the ConfigurationManager
    object o = ConfigurationManager.AppSettings;
    // hack your proxy IInternalConfigSystem into the ConfigurationManager
    FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic);
    s_configSystem.SetValue(null, new ConfigProxy((IInternalConfigSystem)s_configSystem.GetValue(null)));
    // test it
    Console.WriteLine(ConfigurationManager.AppSettings["test"] == "Hello world" ? "Success!" : "Failure!");
  }
}
Pent Ploompuu
A: 

I would try to write an application starter and load the settings from the database to the application domain. So the app doesn't know anything about how it's configuration is generated. Using machiene.config leads directly into dll-hell 2.0.