在运行时更改默认 app.config [英] Change default app.config at runtime

查看:26
本文介绍了在运行时更改默认 app.config的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下问题:
我们有一个加载模块(附加组件)的应用程序.这些模块可能需要 app.config 中的条目(例如 WCF 配置).由于模块是动态加载的,我不想在我的应用程序的 app.config 文件中包含这些条目.
我想做的是以下内容:

I have the following problem:
We have an application that loads modules (add ons). These modules might need entries in the app.config (e.g. WCF configuration). Because the modules are loaded dynamically, I don't want to have these entries in the app.config file of my application.
What I would like to do is the following:

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

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

Note: I do not want to overwrite the default app.config!

它应该透明地工作,以便例如 ConfigurationManager.AppSettings 使用该新文件.

It should work transparently, so that for example ConfigurationManager.AppSettings uses that new file.

在我评估这个问题的过程中,我想出了与这里提供的相同的解决方案:使用 nunit 重新加载 app.config.
不幸的是,它似乎没有做任何事情,因为我仍然从正常的 app.config 中获取数据.

During my evaluation of this problem, I came up with the same solution as is provided here: Reload app.config with nunit.
Unfortunately, it doesn't seem to do anything, because I still get the data from the normal app.config.

我用这段代码来测试它:

I used this code to test it:

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 的其他值,但它会将相同的值打印两次.

It prints the same values twices, although combinedConfig contains other values than the normal app.config.

推荐答案

如果在第一次使用配置系统之前使用,链接问题中的 hack 有效.之后,它不再起作用.
原因:
存在缓存路径的类 ClientConfigPaths.因此,即使使用 SetData 更改路径后,也不会重新读取,因为已经存在缓存值.解决方案是也删除这些:

The hack in the linked question works if it is used before the configuration system is used the first time. After that, it doesn't work any more.
The reason:
There exists a class ClientConfigPaths that caches the paths. So, even after changing the path with SetData, it is not re-read, because there already exist cached values. The solution is to remove these, too:

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

用法如下:

// 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.

If you want to change the used app.config for the whole runtime of your application, simply put AppConfig.Change(tempFileName) without the using somewhere at the start of your application.

这篇关于在运行时更改默认 app.config的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆