Is there a way to override ConfigurationManager.AppSettings?

余生长醉 提交于 2019-11-27 21:12:38

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!");
  }
}

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"].

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.

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.

If you can save you modified config file to disk - you can load alternative config file in different application domain:

AppDomain.CreateDomain("second", null, new AppDomainSetup
{
    ConfigurationFile = options.ConfigPath,
}).DoCallBack(...);

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!