7

実行時にAppSettingsのセクションで定義されたキー/値を更新するのが好きです。Web.configただし、実際にファイルに保存したくありませんWeb.config

多くのモジュール、DLL、ソースコードファイルで構成される巨大なWebアプリケーションがあります。データベース構成、暗号化キー、Webサービスのユーザー名とパスワードに至るまでの一連の重要な情報AppSettingsが、ファイルのセクションに保存されweb.configます。最近のプロジェクト要件では、これらの値を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はできません。一方、これらの値をweb.configファイルに保存しないでください。このファイルは、Web管理者やオペレーター、システムが利用できます。管理者とクラウド管理者。

プログラマーの生活を楽にするために、開発中にAppSettingsセクションに値を追加できるようにしたいのですweb.configが、それらはそこから削除され、後で展開中に安全なストレージに配置されます。ただし、これらの値は、まだ存在しているため、透過的にプログラミングできる必要があります。AppSettingsセクション。

質問:実行時に値を追加してAppSettings、プログラムがWeb.Configに保存せずConfigurationManager.AppSettings["ACriticalKey"]に取得に使用できるようにするにはどうすればよいですか?"VeryCriticalValue"

注意してください:私にメッセージConfigurationManager.AppSettings.Add(item.Key, item.Value);を与えますConfigurationErrorsExceptionThe configuration is read only.

注意:できれば、一部の設定はAppSettings以前と同じように維持できる必要があります

4

4 に答える 4

14

これは古い質問ですが、同じ問題が発生し、SetはAddと同じように機能し、例外をスローしないことがわかりました。次のように、AddをSetに置き換えてください。

ConfigurationManager.AppSettings.Set(item.Key, item.Value);
于 2017-06-07T18:04:36.793 に答える
7

あなたは利用する必要がありますWebConfigurationManager.OpenWebConfiguration()

Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("Variable");
config.AppSettings.Settings.Add("Variable", "valyue");
config.Save();
于 2013-03-27T07:35:12.300 に答える
1

おそらく、このリンクが役立つでしょう。2.0を参照していますが、この方法は4.0でも有効だと思います。

また、ここでの同じ/類似のトピックに関するSOの質問も興味深いかもしれません。

また、実行時にweb.configを変更すると、毎回アプリケーションプールがリサイクルされます。卵を吸う方法を教えようとしているのではなく、誰かの将来の興味のために私がそれを書き留めると思っただけです...Thx。

于 2013-03-27T07:34:54.147 に答える
0

nkvuのおかげで、彼の最初のリンクに移動し、Williarobの投稿「OverrideConfiguration 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
    }
}

これ(または元のバージョンの構成オーバーライド)をインストールするには、グローバルに次の行を追加します。Application_Startのクラス(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

    //...

}
于 2013-03-28T03:21:05.040 に答える