.NET構成(app.config / web.config / settings.settings)


162

デバッグビルドとリリースビルドの構成ファイルが異なる.NETアプリケーションがあります。たとえば、デバッグapp.configファイルは、デバッグが有効になっている開発SQL Serverを指し、リリースターゲットはライブSQL Serverを指します。他の設定もあり、その一部はデバッグ/リリースで異なります。

現在、2つの個別の構成ファイル(debug.app.configとrelease.app.config)を使用しています。プロジェクトにビルドイベントがあり、これがリリースビルドである場合は、release.app.configをapp.configにコピーします。それ以外の場合は、debug.app.configをapp.configにコピーします。

問題は、アプリケーションがsettings.settingsファイルから設定を取得しているように見えるため、Visual Studioでsettings.settingsを開き、設定が変更されたことを通知するので、変更を受け入れ、settings.settingsを保存し、正しい設定を使用するように再構築します。

同様の効果を達成するためのより良い/推奨/推奨される方法はありますか?または同様に、私はこれを完全に間違ってアプローチしましたか?そしてより良いアプローチがありますか?


私は...この上の誰も助け私を..私はデバッグ設定ですべてのチェックボックスをオフにして試してみましたが、それでも私はビンリリースexeファイルをデバッグすることができ、よりウィンドウでデバッグを無効にするためにしたい
Vinothナラヤン

回答:


62

環境ごとに異なる可能性のある構成は、アプリケーションレベルではなく、マシンレベルで保存する必要があります(構成レベルの詳細情報。)

これらは、私が通常マシンレベルで保存する種類の構成要素です。

各環境(開発者、統合、テスト、ステージング、ライブ)がc:\ Windows \ Microsoft.NET \ Framework64 \ v2.0.50727 \ CONFIGディレクトリに独自の固有の設定を持っている場合、アプリケーションコードを環境間で昇格させることができます。ビルド後の変更。

そして明らかに、マシンレベルのCONFIGディレクトリのコンテンツは、アプリとは異なるリポジトリまたは異なるフォルダー構造でバージョン管理されます。configSourceをインテリジェントに使用することで、.configファイルをよりソース管理に適したものにすることができます。

私はこれを7年間、25以上の異なる企業で200を超えるASP.NETアプリケーションで行ってきました。(自慢しようとするのではなく、このアプローチが機能しない状況を見たことがないことを知らせたいだけです。)


3
Webサーバーを制御していないためにマシンレベルの設定を変更できない状況はどうですか?例には、サードパーティのWebサーバーや、企業内の複数の部門間で共有されるWebサーバーが含まれます。
RationalGeek

1
うまくいきません。しかし、仮想マシン、Amazon EC2、およびデルの400ドルのサーバーの時代に、共有マシンで本当に深刻なことをする人はいますか?まったく無力になろうとはしていません-共有Webサーバーで作業している場合は、再評価する必要があると私は本当に思っています。
ポートマン

7
そこには、再評価は、企業レベルで行わなければならない-私は1台のサーバー上の内部サイトのホストで複数のアプリケーションでで働いてきたほとんどの法人
MPritchard

1つのサーバー上の複数のアプリケーションは、アプリケーションがすべて同じ「環境」にある限り問題ありません。つまり、App2のDEVインスタンスと同じサーバー上にあるApp1のLIVEインスタンスは必要ありません。たとえば、SMTP設定はすべてのアプリケーションで共有されます。本番環境では、実際のメールサーバーを指定します。開発では、ディスク上のファイルを指します。
ポートマン

7
これが機能することはわかっていますが、展開を自動化しようとするときに私が推奨することには依然として反しています。設定はアプリケーション固有であり、アプリケーションと一緒にバージョン管理され、それとともに進化する必要があると思います。マシン構成に依存するだけでシフトし、私の意見ではそれを難し​​くします。私は、一緒に変化するものをまとめて、一緒に展開するのが好きです。Devに新しい設定を追加する場合、prodに同等の設定が必要になる可能性があります。
ミゲル・マデロ

51

これは、一部の人々がSettings.settingsおよびApp.configを扱うのに役立つ場合があります。VisualStudio(私の場合はVisual Studio 2008)のSettings.settingsグリッドの値を編集している間、プロパティペインのGenerateDefaultValueInCode属性に注意してください。

GenerateDefaultValueInCodeをTrue(ここではTrueがデフォルトです)に設定すると、デフォルト値はEXE(またはDLL)にコンパイルされます。プレーンテキストエディターで開くと、ファイルに埋め込まれています。

コンソールアプリケーションで作業していて、デフォルトでEXEを使用している場合、アプリケーションは常に同じディレクトリに配置された構成ファイルを無視していました。かなりの悪夢であり、インターネット全体でこれに関する情報はありません。


7
これは、まさにこの週末に私に起こったことです。私のアプリが私のapp.configファイルを無視しているように見える理由を理解しようと、たくさんの髪を引き出しました!Webサービスに接続することになっており、サービスのURLはapp.configにあります。私にはわかりませんが、Web参照を作成すると、Settings.Settingsファイルも作成され、デフォルト値がコードにハードコーディングされました。最後に設定ファイルを見つけて削除したときでも、そのデフォルト値はハードコードに残り、exeに埋め込まれました。非常にフラストレーション!この投稿のおかげで、私はその「機能」を取り除くことができます
Mike K

+1この答えは重要です。設定をapp.configファイルに含める場合は、GenerateDefaultValueInCode属性をFalseに設定します(デフォルトはTrueです)。
Sabuncu 2013年

34

ここに関連する質問があります:

ビルドプロセスの改善

構成ファイルには、設定を上書きする方法が付属しています。

<appSettings file="Local.config">

2つ(またはそれ以上)のファイルをチェックインする代わりに、デフォルトの構成ファイルのみをチェックインし、各ターゲットマシンにLocal.configを配置し、その特定のマシンのオーバーライドを持つappSettingsセクションのみを含めます。

configセクションを使用している場合、同等のものは次のとおりです。

configSource="Local.config"

もちろん、他のマシンからすべてのLocal.configファイルのバックアップコピーを作成し、どこかにチェックインすることをお勧めしますが、実際のソリューションの一部ではありません。各開発者はLocal.configファイルに「無視」を設定して、チェックインされないようにします。これにより、他の全員のファイルが上書きされます。

(実際には "Local.config"と呼ぶ必要はありません。これは私が使用するものです)


14

私が読んでいることから、ビルドプロセスにVisual Studioを使用しているようです。代わりにMSBuildとNantを使用することを考えましたか?

Nantのxml構文は少し奇妙ですが、いったん理解すれば、あなたが言ったことを行うのはかなり簡単になります。

<target name="build">
    <property name="config.type" value="Release" />

    <msbuild project="${filename}" target="Build" verbose="true" failonerror="true">
        <property name="Configuration" value="${config.type}" />
    </msbuild>

    <if test="${config.type == 'Debug'}">
        <copy file=${debug.app.config}" tofile="${app.config}" />
    </if>

    <if test="${config.type == 'Release'}">
        <copy file=${release.app.config}" tofile="${app.config}" />
    </if>

</target>


8

以前はWeb配置プロジェクトを使用していましたが、その後NAntに移行しました。異なる設定ファイルを分岐してコピーする代わりに、現在、構成値をビルドスクリプトに直接埋め込み、xmlpokeタスクを介して構成ファイルに挿入しています。

  <xmlpoke
    file="${stagingTarget}/web.config"
    xpath="/configuration/system.web/compilation/@debug"
    value="true"
  />

どちらの場合でも、構成ファイルには任意の開発者値を含めることができ、本番システムを壊すことなく、開発環境内から問題なく機能します。テストを行うときに開発者がビルドスクリプト変数を勝手に変更する可能性は低いことがわかったため、プロセスの早い段階で各varを追加する必要があるにもかかわらず、私たちが試した他の手法よりも誤って設定を誤ることはまれです。デフォルトでは、dev値はprodにプッシュされません。


7

私の現在の雇用主は、最初に開発レベル(デバッグ、ステージング、ライブなど)をmachine.configファイルに入れることでこの問題を解決しました。次に、それをピックアップして適切な構成ファイルを使用するコードを作成しました。これにより、アプリがデプロイされた後の誤った接続文字列の問題が解決されました。

彼らは最近、machine.config値の値から正しい接続文字列を送り返す中央のWebサービスを作成しました。

これは最善の解決策ですか?おそらくそうではありませんが、彼らにとってはうまくいきます。


1
実際、私はそれが実にエレガントだと思います。なぜなら、私はさまざまなバージョンのconfigが存在しない場合でも、ソリューション内で見えるようにしたいからです。
アナカタ09/12/01

1
これは非常に興味深いソリューションです。この動作の例を見てみたいと思います。
Mike K

5

私がうまく機能したソリューションの1つは、WebDeploymentProjectを使用することでした。選択した構成モード(release / staging / etc ...)に応じて、サイトと発行時に2/3の異なるweb.configファイルがありました。Web.Release.configをコピーして、名前をwebに変更します。 AfterBuildイベントの構成、および不要なもの(Web.Staging.configなど)を削除します。

<Target Name="AfterBuild">
    <!--Web.config -->
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Release.config" DestinationFiles="$(OutputPath)\Web.config" />
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Staging|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Staging.config" DestinationFiles="$(OutputPath)\Web.config" />
    <!--Delete extra files -->
    <Delete Files="$(OutputPath)\Web.Release.config" />
    <Delete Files="$(OutputPath)\Web.Staging.config" />
    <Delete Files="@(ProjFiles)" />
  </Target>


3

私たちのプロジェクトには、dev、qa、uat、prodの構成を維持する必要があるのと同じ問題があります。以下は私たちが従ったものです(MSBuildに精通している場合にのみ適用されます)。

MSBuildをMSBuildコミュニティタスク拡張機能とともに使用します。最初に正しいノードを指定すると、XMLファイル内のエントリを「一括更新」できる「XmlMassUpdate」タスクが含まれます。

実装する:

1)dev envエントリーを含む構成ファイルが1つ必要です。これは、ソリューションの構成ファイルです。

2)「Substitutions.xml」ファイルが必要です。このファイルには、環境ごとに異なるエントリ(主にappSettingsおよびConnectionStrings)のみが含まれています。環境全体で変更されないエントリは、このファイルに入れる必要はありません。それらはソリューションのweb.configファイルに存在でき、タスクには影響されません

3)ビルドファイルで、XML一括更新タスクを呼び出し、適切な環境をパラメーターとして指定します。

以下の例をご覧ください。

    <!-- Actual Config File -->
    <appSettings>
        <add key="ApplicationName" value="NameInDev"/>
        <add key="ThisDoesNotChange" value="Do not put in substitution file" />
    </appSettings>

    <!-- Substitutions.xml -->
    <configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <substitutions>
        <QA>
           <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInQA"/>
           </appSettings>            
        </QA>
        <Prod>
          <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInProd"/>
          </appSettings>            
        </Prod>
     </substitutions>
    </configuration>


<!-- Build.xml file-->

    <Target Name="UpdateConfigSections">
            <XmlMassUpdate ContentFile="Path\of\copy\of\latest web.config" SubstitutionsFile="path\of\substitutionFile" ContentRoot="/configuration" SubstitutionsRoot="/configuration/substitutions/$(Environment)" />
        </Target>

「$ Environment」を「env」に基づいて「QA」または「Prod」に置き換えます。あなたのために構築しています。リカバリー不能なエラーを回避するために、実際の構成ファイル自体ではなく、構成ファイルのコピーで作業する必要があることに注意してください。

ビルドファイルを実行して、更新された構成ファイルをデプロイメント環境に移動するだけで完了です。

より良い概要については、これを読んでください:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx


2

あなたと同じように、「マルチ」app.configも設定しました(例:app.configDEV、app.configTEST、app.config.LOCAL)。私はいくつかの優れた代替案を提案していますが、それがあなたのために機能する方法が好きなら、私は以下を追加します:

私が持っている
<appSettings>
<add key = "Env" value = "[Local] "/> 各アプリケーションのために、私はタイトルバーにUIにこれを追加します。ConfigurationManager.AppSettings.Get(「のEnv」)から。

構成の名前を、対象とする名前に変更するだけです(4つの偶数に対して、多くのデータベース/ WCF構成を持つ8つのアプリを含むプロジェクトがあります)。それぞれにクリックワンスでデプロイするには、プロジェクトの4つの視点を変更して行きます。(これは私が自動化したいです)

古い構成は手動で名前を変更すると「スタック」されるため、変更後は「すべてをクリーンアップ」することを忘れないでください。(私はあなたがsetting.settingの問題を修正すると思います)。

私はこれが本当にうまく機能することを発見しました(ある日、MSBuild / NAntを確認する時間があります)


0

Web.config:

IISでアプリケーションをホストする場合は、Web.configが必要です。Web.configは、IISがKestrelの前でリバースプロキシとして動作する方法を構成するための必須の構成ファイルです。IISでホストする場合は、web.configを維持する必要があります。

AppSetting.json:

IISに関係のないその他すべての場合は、AppSetting.jsonを使用します。AppSetting.jsonはAsp.Net Coreホスティングに使用されます。ASP.NET Coreは「ASPNETCORE_ENVIRONMENT」環境変数を使用して現在の環境を決定します。デフォルトでは、この値を設定せずにアプリケーションを実行すると、自動的にデフォルトで本番環境になり、「AppSetting.production.json」ファイルが使用されます。Visual Studioでデバッグすると、環境が開発に設定され、「AppSetting.json」が使用されます。Windowsでホスティング環境変数を設定する方法については、このWebサイトを参照してください。

App.config:

App.configは.NETで使用される別の構成ファイルで、主にWindowsフォーム、Windowsサービス、コンソールアプリケーション、WPFアプリケーションで使用されます。Asp.Net Coreを起動すると、コンソールアプリケーションapp.configも使用されます。


TL; DR

構成ファイルの選択は、サービス用に選択したホスティング環境によって決まります。IISを使用してサービスをホストしている場合は、Web.configファイルを使用します。他のホスティング環境を使用している場合は、App.configファイルを使用します。構成ファイルを使用したサービスの構成のドキュメントを参照し、ASP.NET Coreの構成 も確認してください


0

上記のasp.netと表示されているので、設定をデータベースに保存し、カスタムキャッシュを使用して取得しませんか?

これを行った理由は、継続的にデータベースを更新する方が、運用ファイルを継続的に更新する許可を取得するよりも簡単であるためです。

カスタムキャッシュの例:

public enum ConfigurationSection
{
    AppSettings
}

public static class Utility
{
    #region "Common.Configuration.Configurations"

    private static Cache cache = System.Web.HttpRuntime.Cache;

    public static String GetAppSetting(String key)
    {
        return GetConfigurationValue(ConfigurationSection.AppSettings, key);
    }

    public static String GetConfigurationValue(ConfigurationSection section, String key)
    {
        Configurations config = null;

        if (!cache.TryGetItemFromCache<Configurations>(out config))
        {
            config = new Configurations();
            config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
            cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
        }

        var result = (from record in config
                      where record.Key == key
                      select record).FirstOrDefault();

        return (result == null) ? null : result.Value;
    }

    #endregion
}

namespace Common.Configuration
{
    public class Configurations : List<Configuration>
    {
        #region CONSTRUCTORS

        public Configurations() : base()
        {
            initialize();
        }
        public Configurations(int capacity) : base(capacity)
        {
            initialize();
        }
        public Configurations(IEnumerable<Configuration> collection) : base(collection)
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud; // Db-Access layer

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
        }

        /// <summary>
        /// Lists one-to-many records.
        /// </summary>
        public Configurations List(ConfigurationSection section)
        {
            using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_MyConfiguration"))
            {
                _crud.Db.AddInParameter(dbCommand, "@Section", DbType.String, section.ToString());

                _crud.List(dbCommand, PopulateFrom);
            }

            return this;
        }

        public void PopulateFrom(DataTable table)
        {
            this.Clear();

            foreach (DataRow row in table.Rows)
            {
                Configuration instance = new Configuration();
                instance.PopulateFrom(row);
                this.Add(instance);
            }
        }

        #endregion
    }

    public class Configuration
    {
        #region CONSTRUCTORS

        public Configuration()
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud;

        public string Section { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
            Clear();
        }

        public void Clear()
        {
            this.Section = "";
            this.Key = "";
            this.Value = "";
        }
        public void PopulateFrom(DataRow row)
        {
            Clear();

            this.Section = row["Section"].ToString();
            this.Key = row["Key"].ToString();
            this.Value = row["Value"].ToString();
        }

        #endregion
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.