我有以下问题:
我们有一个加载模块(附加组件)的应用程序。这些模块可能需要app.config中的条目(例如WCF配置)。因为模块是动态加载的,所以我不希望在应用程序的app.config文件中包含这些条目。
我想做的事情如下:
注意:我不想覆盖默认的app.config!
它应该透明地工作,这样例如ConfigurationManager.AppSettings
就可以使用这个新文件。
在评估这个问题时,我提出了与这里提供的解决方案相同的解决方案:Reload app.config with nunit。
不幸的是,它似乎什么也做不了,因为我仍然从普通的app.config中获取数据。
我使用以下代码对其进行了测试:
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之外的其他值。
发布于 2011-05-27 19:34:52
如果在第一次使用配置系统之前使用,则链接问题中的hack会起作用。在那之后,它就不再工作了。
原因:
存在一个缓存路径的类ClientConfigPaths
。因此,即使在使用SetData
更改路径之后,也不会重新读取它,因为已经存在缓存值。解决方案是将它们也删除:
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。
发布于 2011-05-27 18:11:47
您可以尝试使用Configuration并在运行时添加ConfigurationSection
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
派生的类
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
中的私有字段
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
发布于 2015-02-13 21:15:33
@Daniel解决方案工作正常。为了完整起见,我想分享我的版本:使用using
和位标志缩写的c-sharp corner.中有一个类似的解决方案,有更多解释。
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;
}
https://stackoverflow.com/questions/6150644
复制相似问题