web-dev-qa-db-ja.com

app.config / web.config内の変数

app.configまたはweb.configファイルで次のようなことを行うことは可能ですか?

<appSettings>
 <add key="MyBaseDir" value="C:\MyBase" />
 <add key="Dir1" value="[MyBaseDir]\Dir1"/>
 <add key="Dir2" value="[MyBaseDir]\Dir2"/>
</appSettings>

次に、単に次のように言って、コード内のDir2にアクセスします。

 ConfigurationManager.AppSettings["Dir2"]

これは、app.config全体で1つのエントリのみを変更する必要がある異なるサーバーや場所にアプリケーションをインストールするときに役立ちます。 (コード内のすべての連結を管理できることは知っていますが、この方法を好みます)。

84

良い質問。

あるとは思わない。簡単な方法があればよく知られていると思います。Microsoftは、展開とテストのためにさまざまな構成ファイルを展開するためのメカニズムをVisual Studio 2010で作成しています。

ただし、そうは言っています。 ConnectionStringsセクションには、「| DataDirectory |」と呼ばれる一種のプレースホルダーがあることがわかりました。多分あなたはそこで働いているものを見ることができます...

これはmachine.configそれを示す:

 <connectionStrings>
    <add
        name="LocalSqlServer"
        connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
        providerName="System.Data.SqlClient"
    />
 </connectionStrings>
7
Arjan Einbu

少し複雑ですが、はるかに柔軟な代替手段は、構成セクションを表すクラスを作成することです。あなたのapp.config/web.configファイル、あなたはこれを持つことができます:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <!-- This section must be the first section within the <configuration> node -->
    <configSections>
        <section name="DirectoryInfo" type="MyProjectNamespace.DirectoryInfoConfigSection, MyProjectAssemblyName" />
    </configSections>

    <DirectoryInfo>
        <Directory MyBaseDir="C:\MyBase" Dir1="Dir1" Dir2="Dir2" />
    </DirectoryInfo>
</configuration>

次に、.NETコード(この例ではC#を使用します)で、次のような2つのクラスを作成できます。

using System;
using System.Configuration;

namespace MyProjectNamespace {

    public class DirectoryInfoConfigSection : ConfigurationSection {

        [ConfigurationProperty("Directory")]
        public DirectoryConfigElement Directory {
            get {
                return (DirectoryConfigElement)base["Directory"];
            }
    }

    public class DirectoryConfigElement : ConfigurationElement {

        [ConfigurationProperty("MyBaseDir")]
        public String BaseDirectory {
            get {
                return (String)base["MyBaseDir"];
            }
        }

        [ConfigurationProperty("Dir1")]
        public String Directory1 {
            get {
                return (String)base["Dir1"];
            }
        }

        [ConfigurationProperty("Dir2")]
        public String Directory2 {
            get {
                return (String)base["Dir2"];
            }
        }
        // You can make custom properties to combine your directory names.
        public String Directory1Resolved {
            get {
                return System.IO.Path.Combine(BaseDirectory, Directory1);
            }
        }
    }
}

最後に、プログラムコードで、app.config変数、新しいクラスを使用して、この方法で:

DirectoryInfoConfigSection config =
  (DirectoryInfoConfigSection)ConfigurationManager.GetSection("DirectoryInfo");
String dir1Path = config.Directory.Directory1Resolved;  // This value will equal "C:\MyBase\Dir1"
22
Matt Hamsmith

私の拡張ライブラリを使用して達成できます: http://nuget.org/List/Packages/Expansive ソースはここから入手できます: https://github.com/anderly/Expansive

14
anderly

私はこの質問を見たと思った。

要するに、いや、アプリケーション構成内に変数補間はありません。

2つの選択肢があります

  1. 独自のロールを実行して、実行時に変数を置き換えることができます
  2. ビルド時に、アプリケーション構成をターゲット展開環境の特定の仕様に合わせてマッサージします。これについての詳細は configuration-nightmareで対処
4
Scott Weinstein

いくつかのオプションがあります。これは、構成ファイルを処理して、変数を正しい値に置き換えてビルド/デプロイするステップで行うことができます。

別のオプションは、これをサポートする独自の構成セクションを定義することです。たとえば、次のxmlを想像してください。

<variableAppSettings>
 <variables>
    <add key="@BaseDir" value="c:\Programs\Widget"/>
 </variables>
 <appSettings>
    <add key="PathToDir" value="@BaseDir\Dir1"/>
 </appSettings>
</variableAppSettings>

これで、実行時に変数の置換を処理するカスタム構成オブジェクトを使用してこれを実装します。

3
JoshBerke

通常、web.configの各設定にアクセスするためのプロパティを持つ静的クラスを作成します。

public static class ConfigManager 
{
    public static string MyBaseDir
    {
        return ConfigurationManager.AppSettings["MyBaseDir"].toString();
    }

    public static string Dir1
    {
        return MyBaseDir + ConfigurationManager.AppSettings["Dir1"].toString();
    }

}

通常、このクラスで必要な場合は型変換も行います。それはあなたの設定への入力されたアクセスを持つことができ、設定が変更された場合、あなたはそれらを一か所で編集することができます。

通常、設定をこのクラスに置き換えることは比較的簡単で、メンテナンス性が大幅に向上します。

3
Martin

内部<appSettings>アプリケーションキーを作成できます。

<add key="KeyName" value="Keyvalue"/>

後で、次を使用してこれらの値にアクセスできます。

ConfigurationManager.AppSettings["Keyname"]
2
Sergio

説明するシナリオのapp.configで環境変数を使用できます

<configuration>
  <appSettings>
    <add key="Dir1" value="%MyBaseDir%\Dir1"/>
  </appSettings>
</configuration>

次に、簡単にパスを取得できます:

var pathFromConfig = ConfigurationManager.AppSettings["Dir1"];
var expandedPath = Environment.ExpandEnvironmentVariables(pathFromConfig);
2
autocro

DslConfig をお勧めします。 DslConfigを使用すると、Global Configの階層構成ファイル、サーバーホストごとの構成を使用して、各サーバーホスト上のアプリケーションごとに構成できます(AppSpikeを参照)。
これが複雑な場合は、グローバル設定のVariables.varを使用できます
Varibales.varで設定するだけ

baseDir = "C:\MyBase"
Var["MyBaseDir"] = baseDir
Var["Dir1"] = baseDir + "\Dir1"
Var["Dir2"] = baseDir + "\Dir2"

そして、設定値を取得します

Configuration config = new DslConfig.BooDslConfiguration()
config.GetVariable<string>("MyBaseDir")
config.GetVariable<string>("Dir1")
config.GetVariable<string>("Dir2")
1
Johannes

私はこの解決策を思いつきました:

  1. アプリケーションのSettings.settingsで、変数ConfigurationBaseを定義しました(type = string Scope = Applicationを使用)
  2. Settings.settingsのターゲット属性に変数を導入しました。これらの属性はすべてScope = Userに設定する必要がありました
  3. App.xaml.csで、ConfigurationBaseの場合、値を読み取ります
  4. App.xaml.csで、すべての変数をConfigurationBase値に置き換えました。実行時に値を置換するには、属性をScopr = Userに設定する必要がありました

すべての属性を手動で変更する必要があるため、app.xaml.csでそれを考慮する必要があるため、このソリューションにはあまり満足していません。

ここにApp.xaml.csからのコードスニペット:

string configBase = Settings.Default.ConfigurationBase;
Settings.Default.CommonOutput_Directory = Settings.Default.CommonOutput_Directory.Replace("${ConfigurationBase}", configBase);

[〜#〜] update [〜#〜]

改善が見つかりました(再びapp.xaml.csのコードスニペット):

string configBase = Settings.Default.ConfigurationBase;

foreach (SettingsProperty settingsProperty in Settings.Default.Properties)
{
    if (!settingsProperty.IsReadOnly && settings.Default[settingsProperty.Name] is string)
    {
        Settings.Default[settingsProperty.Name] = ((string)Settings.Default[settingsProperty.Name]).Replace("${ConfigurationBase}", configBase);
    }
}

これで、Type = stringおよびScope = Userを持つ設定のすべての属性に対して置換が機能します。私はこの方法が好きだと思います。

PDATE2

どうやらプロパティを実行する場合、Scope = Applicationを設定する必要はありません。

0
anhoppe

Matt Hamsmithのソリューションに従うことをお勧めします。実装するのが問題なら、これをAppSettingsクラスのバックグラウンドで実装する拡張メソッドを作成してみませんか?

何かのようなもの:

    public static string GetValue(this NameValueCollection settings, string key)
    {

    }

メソッド内で、Linqを使用してDictionaryInfoConfigSectionを検索し、一致するキーを持つ値を返します。ただし、設定ファイルを次の行に沿って更新する必要があります。

<appSettings>
  <DirectoryMappings>
    <DirectoryMap key="MyBaseDir" value="C:\MyBase" />
    <DirectoryMap key="Dir1" value="[MyBaseDir]\Dir1"/>
    <DirectoryMap key="Dir2" value="[MyBaseDir]\Dir2"/>
  </DirectoryMappings>
</appSettings>
0
Rich

3つの可能な解決策

私はパーティーに遅れることを知っています。変数構成設定の問題に対する新しい解決策があるかどうかを探していました。私が過去に使用したソリューションに触れるいくつかの答えがありますが、ほとんどは少し複雑に思えます。同じ問題に苦しんでいる人々を助けるために、古いソリューションを見て、実装をまとめると思いました。

この例では、コンソールアプリケーションで次のアプリ設定を使用しました。

_<appSettings>
    <add key="EnvironmentVariableExample" value="%BaseDir%\bin"/>
    <add key="StaticClassExample" value="bin"/>
    <add key="InterpollationExample" value="{0}bin"/>
  </appSettings>
_

1.環境変数を使用する

Autocro autocro's answer に触れたと思います。 Visual Studioを閉じることなく、ビルドまたはデバッグするのに十分な実装を実行しています。私はこのソリューションを以前に使用しました...

  • MSBuild変数を使用するビルド前イベントを作成します

    警告:簡単には置き換えられない変数を使用するため、プロジェクト名または変数名に似た名前を使用してください。

    SETX BaseDir "$(ProjectDir)"

  • 変数をリセットします。次のようなものを使用します。

    スタックオーバーフローで環境変数を更新する

  • コードで設定を使用します。

'

_private void Test_Environment_Variables()
{
    string BaseDir = ConfigurationManager.AppSettings["EnvironmentVariableExample"];
    string ExpandedPath = Environment.ExpandEnvironmentVariables(BaseDir).Replace("\"", ""); //The function addes a " at the end of the variable
    Console.WriteLine($"From within the C# Console Application {ExpandedPath}");
}
_

'

2.文字列補間を使用します。

  • String.Format()関数を使用します

`

_private void Test_Interpollation()
{
    string ConfigPath = ConfigurationManager.AppSettings["InterpollationExample"];
    string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
    string ExpandedPath = string.Format(ConfigPath, SolutionPath.ToString());
    Console.WriteLine($"Using old interpollation {ExpandedPath}");
}
_

`

3.静的クラスを使用して、これは私が主に使用するソリューションです。

  • 実装

`

_private void Test_Static_Class()
{
    Console.WriteLine($"Using a static config class {Configuration.BinPath}");
}
_

`

  • 静的クラス

`

_static class Configuration
{
    public static string BinPath
    {
        get
        {
            string ConfigPath = ConfigurationManager.AppSettings["StaticClassExample"];
            string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
            return SolutionPath + ConfigPath;
        }
    }
}
_

`

プロジェクトコード:

App.config:

_<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
  <appSettings>
    <add key="EnvironmentVariableExample" value="%BaseDir%\bin"/>
    <add key="StaticClassExample" value="bin"/>
    <add key="InterpollationExample" value="{0}bin"/>
  </appSettings>
</configuration>
_

Program.cs

_using System;
using System.Configuration;
using System.IO;

namespace ConfigInterpollation
{
    class Program
    {
        static void Main(string[] args)
        {
            new Console_Tests().Run_Tests();
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        }        
    }

    internal class Console_Tests
    {
        public void Run_Tests()
        {
            Test_Environment_Variables();
            Test_Interpollation();
            Test_Static_Class();
        }
        private void Test_Environment_Variables()
        {
            string ConfigPath = ConfigurationManager.AppSettings["EnvironmentVariableExample"];
            string ExpandedPath = Environment.ExpandEnvironmentVariables(ConfigPath).Replace("\"", "");
            Console.WriteLine($"Using environment variables {ExpandedPath}");
        }

        private void Test_Interpollation()
        {
            string ConfigPath = ConfigurationManager.AppSettings["InterpollationExample"];
            string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
            string ExpandedPath = string.Format(ConfigPath, SolutionPath.ToString());
            Console.WriteLine($"Using interpollation {ExpandedPath}");
        }

        private void Test_Static_Class()
        {
            Console.WriteLine($"Using a static config class {Configuration.BinPath}");
        }
    }

    static class Configuration
    {
        public static string BinPath
        {
            get
            {
                string ConfigPath = ConfigurationManager.AppSettings["StaticClassExample"];
                string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
                return SolutionPath + ConfigPath;
            }
        }
    }
}
_

ビルド前のイベント:

プロジェクト設定->ビルドイベント

0
StormChild

構成ファイル内でappSettingsキーを定義するために変数を宣言して使用できるとは思いません。私はいつもあなたのようなコードで連結を管理してきました。

0

私はあなたが望むものに少し苦労していますが、オーバーライドファイルをアプリ設定に追加してから、そのオーバーライドファイルを環境ごとに設定することができます。

<appSettings file="..\OverrideSettings.config">
0
Andrew Barrett

多くのアイテムを同様の値で設定する必要がある製品をロールアウトするには、XMLを読み取り、渡されたパラメーターに基づいて更新する小さなコンソールアプリを使用します。これらは、ユーザーに必要な情報。

0
cjk