首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在运行时更改默认app.config

在运行时更改默认app.config
EN

Stack Overflow用户
提问于 2011-05-27 17:59:33
回答 8查看 84.1K关注 0票数 134

我有以下问题:

我们有一个加载模块(附加组件)的应用程序。这些模块可能需要app.config中的条目(例如WCF配置)。因为模块是动态加载的,所以我不希望在应用程序的app.config文件中包含这些条目。

我想做的事情如下:

  • 在内存中创建一个新的app.config,其中包含模块中的配置部分
  • 告诉我的应用程序使用新的app.config

注意:我不想覆盖默认的app.config!

它应该透明地工作,这样例如ConfigurationManager.AppSettings就可以使用这个新文件。

在评估这个问题时,我提出了与这里提供的解决方案相同的解决方案:Reload app.config with nunit

不幸的是,它似乎什么也做不了,因为我仍然从普通的app.config中获取数据。

我使用以下代码对其进行了测试:

代码语言:javascript
复制
Console.WriteLine(ConfigurationManager.AppSettings["SettingA"]);
Console.WriteLine(Settings.Default.Setting);

var combinedConfig = string.Format(CONFIG2, CONFIG);
var tempFileName = Path.GetTempFileName();
using (var writer = new StreamWriter(tempFileName))
{
    writer.Write(combinedConfig);
}

using(AppConfig.Change(tempFileName))
{
    Console.WriteLine(ConfigurationManager.AppSettings["SettingA"]);
    Console.WriteLine(Settings.Default.Setting);
}

它打印相同的值两次,尽管combinedConfig包含普通app.config之外的其他值。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2011-05-27 19:34:52

如果在第一次使用配置系统之前使用,则链接问题中的hack会起作用。在那之后,它就不再工作了。

原因:

存在一个缓存路径的类ClientConfigPaths。因此,即使在使用SetData更改路径之后,也不会重新读取它,因为已经存在缓存值。解决方案是将它们也删除:

代码语言:javascript
复制
using System;
using System.Configuration;
using System.Linq;
using System.Reflection;

public abstract class AppConfig : IDisposable
{
    public static AppConfig Change(string path)
    {
        return new ChangeAppConfig(path);
    }

    public abstract void Dispose();

    private class ChangeAppConfig : AppConfig
    {
        private readonly string oldConfig =
            AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();

        private bool disposedValue;

        public ChangeAppConfig(string path)
        {
            AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path);
            ResetConfigMechanism();
        }

        public override void Dispose()
        {
            if (!disposedValue)
            {
                AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", oldConfig);
                ResetConfigMechanism();


                disposedValue = true;
            }
            GC.SuppressFinalize(this);
        }

        private static void ResetConfigMechanism()
        {
            typeof(ConfigurationManager)
                .GetField("s_initState", BindingFlags.NonPublic | 
                                         BindingFlags.Static)
                .SetValue(null, 0);

            typeof(ConfigurationManager)
                .GetField("s_configSystem", BindingFlags.NonPublic | 
                                            BindingFlags.Static)
                .SetValue(null, null);

            typeof(ConfigurationManager)
                .Assembly.GetTypes()
                .Where(x => x.FullName == 
                            "System.Configuration.ClientConfigPaths")
                .First()
                .GetField("s_current", BindingFlags.NonPublic | 
                                       BindingFlags.Static)
                .SetValue(null, null);
        }
    }
}

用法如下:

代码语言:javascript
复制
// the default app.config is used.
using(AppConfig.Change(tempFileName))
{
    // the app.config in tempFileName is used
}
// the default app.config is used.

如果您想要更改应用程序整个运行时使用的app.config,只需将AppConfig.Change(tempFileName)放在应用程序开始时的某个位置,而不使用using。

票数 289
EN

Stack Overflow用户

发布于 2011-05-27 18:11:47

您可以尝试使用Configuration并在运行时添加ConfigurationSection

代码语言:javascript
复制
Configuration applicationConfiguration = ConfigurationManager.OpenMappedExeConfiguration(
                        new ExeConfigurationFileMap(){ExeConfigFilename = path_to_your_config,
                        ConfigurationUserLevel.None
                        );

applicationConfiguration.Sections.Add("section",new YourSection())
applicationConfiguration.Save(ConfigurationSaveMode.Full,true);

编辑:这里的是基于反射的解决方案(虽然不是很好)

创建从IInternalConfigSystem派生的类

代码语言:javascript
复制
public class ConfigeSystem: IInternalConfigSystem
{
    public NameValueCollection Settings = new NameValueCollection();
    #region Implementation of IInternalConfigSystem

    public object GetSection(string configKey)
    {
        return Settings;
    }

    public void RefreshConfig(string sectionName)
    {
        //throw new NotImplementedException();
    }

    public bool SupportsUserConfig { get; private set; }

    #endregion
}

然后通过反射将其设置为ConfigurationManager中的私有字段

代码语言:javascript
复制
        ConfigeSystem configSystem = new ConfigeSystem();
        configSystem.Settings.Add("s1","S");

        Type type = typeof(ConfigurationManager);
        FieldInfo info = type.GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static);
        info.SetValue(null, configSystem);

        bool res = ConfigurationManager.AppSettings["s1"] == "S"; // return true
票数 11
EN

Stack Overflow用户

发布于 2015-02-13 21:15:33

@Daniel解决方案工作正常。为了完整起见,我想分享我的版本:使用using和位标志缩写的c-sharp corner.中有一个类似的解决方案,有更多解释。

代码语言:javascript
复制
using System;//AppDomain
using System.Linq;//Where
using System.Configuration;//app.config
using System.Reflection;//BindingFlags

    /// <summary>
    /// Use your own App.Config file instead of the default.
    /// </summary>
    /// <param name="NewAppConfigFullPathName"></param>
    public static void ChangeAppConfig(string NewAppConfigFullPathName)
    {
        AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", NewAppConfigFullPathName);
        ResetConfigMechanism();
        return;
    }

    /// <summary>
    /// Remove cached values from ClientConfigPaths.
    /// Call this after changing path to App.Config.
    /// </summary>
    private static void ResetConfigMechanism()
    {
        BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Static;
        typeof(ConfigurationManager)
            .GetField("s_initState", Flags)
            .SetValue(null, 0);

        typeof(ConfigurationManager)
            .GetField("s_configSystem", Flags)
            .SetValue(null, null);

        typeof(ConfigurationManager)
            .Assembly.GetTypes()
            .Where(x => x.FullName == "System.Configuration.ClientConfigPaths")
            .First()
            .GetField("s_current", Flags)
            .SetValue(null, null);
        return;
    }
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6150644

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档