C# 如何在运行时更新(添加/修改/删除)web.config 的 AppSettings 部分中的键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15653621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Update (Add/Modify/Delete) keys in AppSettings section of web.config at runtime
提问by AaA
I like to Update keys/Values defined in AppSettings
section of Web.config
at runtime. however I DO NOT want to actually save them to Web.config
file.
我喜欢更新在运行时AppSettings
部分定义的键/值Web.config
。但是我不想将它们实际保存到Web.config
文件中。
I have a huge web application that have consists of many modules, DLLs and source code files. A bunch of critical information ranged from database configuration, encryption keys, username and passwords for webservices are saved in AppSettings
section of the web.config
file. Recent project requirement needs me to move these values out of web.config
and keep in a secure storage.
我有一个巨大的 Web 应用程序,它包含许多模块、DLL 和源代码文件。从数据库配置、加密密钥、Web 服务的用户名和密码等一系列关键信息保存在文件的AppSettings
部分中web.config
。最近的项目要求需要我将这些值移出web.config
并保存在安全存储中。
I already secured these values in an external location and I can read them back when application starts.
我已经在外部位置保护了这些值,并且可以在应用程序启动时读取它们。
here is the sample code.
这是示例代码。
Global.asax
全球.asax
public class Global: System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
Dictionary<string, string> secureConfig = new Dictionary<string,string>{};
// --------------------------------------------------------------------
// Here I read and decrypt keys and add them to secureConfig dictionary
// To test assume the following line is a key stored in secure sotrage.
//secureConfig = SecureConfig.LoadConfig();
secureConfig.Add("ACriticalKey","VeryCriticalValue");
// --------------------------------------------------------------------
foreach (KeyValuePair<string, string> item in secureConfig) {
ConfigurationManager.AppSettings.Add(item.Key, item.Value);
}
}
}
As you may noticed it is not feasible to change references to AppSettings
in a massive code created by multiple programming teams to read their settings from my secureConfig dictionary
and on the other hand I should not save these values in web.config
file which is available to web administrators and operators, system admins and cloud admins.
您可能已经注意到,AppSettings
在多个编程团队创建的大量代码中更改引用以从我的设置中读取它们的设置是不可行的,secureConfig dictionary
另一方面,我不应该将这些值保存在web.config
可供 Web 管理员和操作员使用的文件中,系统管理员和云管理员。
To Make programmers life easier, I want to let them add their values to AppSettings
section of web.config
during development, but they will be removed from there and put to secure storage later during deployment, however these values should be available to program transparently as they are still in AppSettings
section.
为了让程序员的生活更轻松,我想让他们在开发过程中将他们的值添加到AppSettings
部分web.config
,但他们将在部署期间从那里删除并放在安全存储中,但是这些值应该可以透明地编程,因为它们仍然在AppSettings
部分。
Question: how can I add values to AppSettings
at runtime so program can read them using ConfigurationManager.AppSettings["ACriticalKey"]
to get "VeryCriticalValue"
without saving them in Web.Config?
问:我怎么能添加值AppSettings
在运行时使程序可以读取他们用ConfigurationManager.AppSettings["ACriticalKey"]
得到"VeryCriticalValue"
,但不保存他们的Web.Config?
Please note: ConfigurationManager.AppSettings.Add(item.Key, item.Value);
gives me ConfigurationErrorsException
with message The configuration is read only.
请注意:ConfigurationManager.AppSettings.Add(item.Key, item.Value);
给我ConfigurationErrorsException
留言The configuration is read only.
Please note: Preferably some settings should be able to stay in AppSettings
as before
请注意:最好一些设置应该能够保持AppSettings
原样
采纳答案by AaA
Thanks to nkvu which directed me to a his first link which in turn sent me to Williarob's post "Override Configuration Manager" I managed to find a solution to my question.
感谢 nkvu 将我引导到他的第一个链接,该链接又将我发送到Williarob的帖子“覆盖配置管理器”,我设法找到了我的问题的解决方案。
The mentioned blog post covers how to read settings from another XML file and it works with both windowed applications and web applications (with a little modification in config file name and path). Although this blog written on 2010 it is still working fine with .NET4 without problem.
提到的博客文章介绍了如何从另一个 XML 文件读取设置,它适用于窗口应用程序和 Web 应用程序(对配置文件名和路径稍作修改)。尽管这篇博客写于 2010 年,但它在 .NET4 上仍然可以正常工作,没有问题。
However as I was going to read my configuration from a secure device, I simplified the class and here is how to use the classes provided by Williarob
然而,当我要从安全设备读取我的配置时,我简化了类,这里是如何使用Williarob提供的类
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Internal;
using System.Linq;
using System.Reflection;
namespace Williablog.Core.Configuration {
public sealed class ConfigSystem: IInternalConfigSystem {
private static IInternalConfigSystem clientConfigSystem;
private object appsettings;
private object connectionStrings;
/// <summary>
/// Re-initializes the ConfigurationManager, allowing us to merge in the settings from Core.Config
/// </summary>
public static void Install() {
FieldInfo[] fiStateValues = null;
Type tInitState = typeof(System.Configuration.ConfigurationManager).GetNestedType("InitState", BindingFlags.NonPublic);
if (null != tInitState) {
fiStateValues = tInitState.GetFields();
}
FieldInfo fiInit = typeof(System.Configuration.ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static);
FieldInfo fiSystem = typeof(System.Configuration.ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static);
if (fiInit != null && fiSystem != null && null != fiStateValues) {
fiInit.SetValue(null, fiStateValues[1].GetValue(null));
fiSystem.SetValue(null, null);
}
ConfigSystem confSys = new ConfigSystem();
Type configFactoryType = Type.GetType("System.Configuration.Internal.InternalConfigSettingsFactory, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
IInternalConfigSettingsFactory configSettingsFactory = (IInternalConfigSettingsFactory) Activator.CreateInstance(configFactoryType, true);
configSettingsFactory.SetConfigurationSystem(confSys, false);
Type clientConfigSystemType = Type.GetType("System.Configuration.ClientConfigurationSystem, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
clientConfigSystem = (IInternalConfigSystem) Activator.CreateInstance(clientConfigSystemType, true);
}
#region IInternalConfigSystem Members
public object GetSection(string configKey) {
// get the section from the default location (web.config or app.config)
object section = clientConfigSystem.GetSection(configKey);
switch (configKey) {
case "appSettings":
// Return cached version if exists
if (this.appsettings != null) {
return this.appsettings;
}
// create a new collection because the underlying collection is read-only
var cfg = new NameValueCollection();
// If an AppSettings section exists in Web.config, read and add values from it
if (section is NameValueCollection) {
NameValueCollection localSettings = (NameValueCollection) section;
foreach (string key in localSettings) {
cfg.Add(key, localSettings[key]);
}
}
// --------------------------------------------------------------------
// Here I read and decrypt keys and add them to secureConfig dictionary
// To test assume the following line is a key stored in secure sotrage.
//secureConfig = SecureConfig.LoadConfig();
secureConfig.Add("ACriticalKey", "VeryCriticalValue");
// --------------------------------------------------------------------
foreach (KeyValuePair<string, string> item in secureConfig) {
if (cfg.AllKeys.Contains(item.Key)) {
cfg[item.Key] = item.Value;
} else {
cfg.Add(item.Key, item.Value);
}
}
// --------------------------------------------------------------------
// Cach the settings for future use
this.appsettings = cfg;
// return the merged version of the items from secure storage and appsettings
section = this.appsettings;
break;
case "connectionStrings":
// Return cached version if exists
if (this.connectionStrings != null) {
return this.connectionStrings;
}
// create a new collection because the underlying collection is read-only
ConnectionStringsSection connectionStringsSection = new ConnectionStringsSection();
// copy the existing connection strings into the new collection
foreach (ConnectionStringSettings connectionStringSetting in ((ConnectionStringsSection) section).ConnectionStrings) {
connectionStringsSection.ConnectionStrings.Add(connectionStringSetting);
}
// --------------------------------------------------------------------
// Again Load connection strings from secure storage and merge like below
// connectionStringsSection.ConnectionStrings.Add(connectionStringSetting);
// --------------------------------------------------------------------
// Cach the settings for future use
this.connectionStrings = connectionStringsSection;
// return the merged version of the items from secure storage and appsettings
section = this.connectionStrings;
break;
}
return section;
}
public void RefreshConfig(string sectionName) {
if (sectionName == "appSettings") {
this.appsettings = null;
}
if (sectionName == "connectionStrings") {
this.connectionStrings = null;
}
clientConfigSystem.RefreshConfig(sectionName);
}
public bool SupportsUserConfig { get { return clientConfigSystem.SupportsUserConfig; } }
#endregion
}
}
To install this (or original version of configuration override) add following line to your Global. class (Global.asax.cs) in Application_Start
要安装此(或配置覆盖的原始版本),请将以下行添加到您的 Global. Application_Start 中的类 (Global.asax.cs)
Williablog.Core.Configuration.ConfigSystem .Install();
like below:
像下面这样:
public class Global: System.Web.HttpApplication {
//...
#region protected void Application_Start(...)
protected void Application_Start(object sender, EventArgs e) {
Williablog.Core.Configuration.ConfigSystem .Install();
//...
}
#endregion
//...
}
回答by nkvu
Perhaps thislink will help. It references 2.0 but I believe the method is still valid in 4.0.
也许这个链接会有所帮助。它引用了 2.0,但我相信该方法在 4.0 中仍然有效。
Also, the SO question on the same/similar topic heremay be of interest.
此外,关于此处相同/相似主题的 SO 问题可能会引起兴趣。
Also, modifying the web.config at runtime should cause an application pool recycle each time. Not trying to tell you how to suck eggs, just thought I'd note it for anyone's prospective interest...Thx.
此外,在运行时修改 web.config 应该会导致每次应用程序池回收。不是想告诉你如何吸鸡蛋,只是想我会为了任何人的潜在兴趣而注意到它......谢谢。
回答by Rajesh Subramanian
You need to make use of WebConfigurationManager.OpenWebConfiguration()
你需要利用 WebConfigurationManager.OpenWebConfiguration()
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("Variable");
config.AppSettings.Settings.Add("Variable", "valyue");
config.Save();
回答by Sergio Flores
I know this is an old question, but I ran into the same problem and I found that Set works in the same way as Add, and does not throw an exception, so just replace Add with Set, like so:
我知道这是一个老问题,但我遇到了同样的问题,我发现 Set 的工作方式与 Add 的工作方式相同,并且不会引发异常,因此只需将 Add 替换为 Set,如下所示:
ConfigurationManager.AppSettings.Set(item.Key, item.Value);