[英]How to Update (Add/Modify/Delete) keys in AppSettings section of web.config at runtime
我喜歡在運行時更新Web.config
AppSettings
部分中定義的鍵/值。 但是我不想將它們實際保存到Web.config
文件中。
我有一個巨大的Web應用程序,包含許多模塊,DLL和源代碼文件。 一堆關鍵信息包括數據庫配置,加密密鑰,用戶名和web服務密碼,都保存在web.config
文件的AppSettings
部分。 最近的項目要求需要我將這些值從web.config
移出並保存在安全的存儲中。
我已經在外部位置保護了這些值,我可以在應用程序啟動時讀回它們。
這是示例代碼。
Global.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);
}
}
}
您可能已經注意到,在由多個編程團隊創建的大量代碼中更改對AppSettings
引用以從我的secureConfig dictionary
讀取其設置是secureConfig dictionary
,另一方面,我不應將這些值保存在web.config
文件中,該文件可用於Web管理員和操作員,系統管理員和雲管理員。
為了讓程序員的生活更輕松,我想讓他們在開發期間將他們的值添加到web.config
AppSettings
部分,但是他們將從那里刪除並在部署期間放入安全存儲,但是這些值應該可以透明地編程為它們仍然在AppSettings
部分。
問題 :如何在運行時向AppSettings
添加值,以便程序可以使用ConfigurationManager.AppSettings["ACriticalKey"]
讀取它們以獲取"VeryCriticalValue"
而不將它們保存在Web.Config中?
請注意 : ConfigurationManager.AppSettings.Add(item.Key, item.Value);
給我帶有消息The configuration is read only.
ConfigurationErrorsException
The configuration is read only.
請注意 :最好一些設置應該像以前一樣保留在AppSettings
中
我知道這是一個老問題,但我遇到了同樣的問題,我發現Set的工作方式與Add相同,並且不會拋出異常,所以只需將Add替換為Set,如下所示:
ConfigurationManager.AppSettings.Set(item.Key, item.Value);
您需要使用WebConfigurationManager.OpenWebConfiguration()
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("Variable");
config.AppSettings.Settings.Add("Variable", "valyue");
config.Save();
感謝nkvu指導我到他的第一個鏈接,然后將我發送到Williarob的帖子“ Override Configuration Manager ”,我設法找到了我的問題的解決方案。
上面提到的博客文章介紹了如何從另一個XML文件中讀取設置,它適用於窗口化應用程序和Web應用程序(在配置文件名和路徑中稍作修改)。 盡管這篇博客是在2010年寫的,但它仍然可以正常使用.NET4而沒有問題。
但是當我要從安全設備讀取配置時,我簡化了類,這里是如何使用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
}
}
要安裝此(或配置覆蓋的原始版本),請將以下行添加到Global。 Application_Start中的class(Global.asax.cs)
Williablog.Core.Configuration.ConfigSystem .Install();
如下:
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
//...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.