Variablen in app.config / web.config

92

Ist es möglich, in den Dateien app.configoder Folgendes zu tun web.config?

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

Ich möchte dann in meinem Code auf Dir2 zugreifen, indem ich einfach sage:

 ConfigurationManager.AppSettings["Dir2"]

Dies hilft mir, wenn ich meine Anwendung auf verschiedenen Servern und Standorten installiere, an denen ich nur EINEN Eintrag in meinem gesamten ändern muss app.config. (Ich weiß, dass ich die gesamte Verkettung im Code verwalten kann, aber ich bevorzuge es auf diese Weise).

DeeStackOverflow
quelle
Ich denke, er spricht über das Definieren von Variablen, die in appSettings-Schlüsseln direkt in Konfigurationsdateien verwendet werden sollen.
Michaël Carpentier
1
Ich habe auch die XML-Deklaration <! ENTITY> ausgecheckt, sie wird jedoch aufgrund der Art und Weise, wie MS mit web.config-Dateien umgeht, nicht unterstützt.
Chilltemp
Danke für Ihr Bemühen. Ich ziehe es vor, keinen Code zu ändern. Der Code enthält bereits die Anweisung: string dir2 = ConfigurationManager.AppSettings ["Dir2"]. Ich möchte nur die app.config bereinigen, die jetzt value = "D: \ blahdir \ Dir2" anstelle von value = "[MyBaseDir] \ Dir2"
DeeStackOverflow

Antworten:

7

Gute Frage.

Ich glaube nicht. Ich glaube, es wäre ziemlich bekannt gewesen, wenn es einen einfachen Weg gegeben hätte, und ich sehe, dass Microsoft in Visual Studio 2010 einen Mechanismus zum Bereitstellen verschiedener Konfigurationsdateien für die Bereitstellung und den Test erstellt.

Nachdem dies gesagt wurde; Ich habe festgestellt, dass Sie in diesem ConnectionStringsAbschnitt eine Art Platzhalter namens "| DataDirectory |" haben. Vielleicht könnten Sie einen Blick darauf werfen, was dort am Werk ist ...

Hier ist ein Stück machine.configdavon:

 <connectionStrings>
    <add
        name="LocalSqlServer"
        connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
        providerName="System.Data.SqlClient"
    />
 </connectionStrings>
Arjan Einbu
quelle
Das sind interessante Informationen. Möglicherweise wird auf Variablen über das Pipe-Symbol ("|") zugegriffen? Hmm .. Ich frage mich, ob das funktionieren wird: <add key = "Dir2" value = "| MyBaseDir | \ Dir2" />
DeeStackOverflow
4
Der DataDirectory-Wert ist tatsächlich ein Datenelement in der AppDomain. Sie können den Wert mithilfe von AppDomain.CurrentDomain.SetData ("DataDirectory", dataPath) überschreiben. Ich habe nicht getestet, ob Sie andere Variablen wie diese definieren und sie "automatisch erweitern" können ...
Peter Lillevold
22

Eine etwas kompliziertere, aber weitaus flexiblere Alternative besteht darin, eine Klasse zu erstellen, die einen Konfigurationsabschnitt darstellt. In Ihrer app.config/ web.configDatei können Sie Folgendes haben:

<?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>

Anschließend können Sie in Ihrem .NET-Code (in meinem Beispiel C #) zwei Klassen wie die folgende erstellen:

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);
            }
        }
    }
}

Schließlich können Sie in Ihrem Programmcode app.configmithilfe Ihrer neuen Klassen auf folgende Weise auf Ihre Variablen zugreifen :

DirectoryInfoConfigSection config =
  (DirectoryInfoConfigSection)ConfigurationManager.GetSection("DirectoryInfo");
String dir1Path = config.Directory.Directory1Resolved;  // This value will equal "C:\MyBase\Dir1"
Matt Hamsmith
quelle
1
Vielen Dank, aber ich versuche dies zu tun, ohne Code zu ändern, da dies derzeit schmerzhaft ist.
DeeStackOverflow
Es gibt einen kleinen Fehler in der letzten Codezeile (ohne geschweifte Klammern): "return System.IO.Path.Combine (MyBaseDir, Dir1);" sollte stattdessen "System.IO.Path.Combine (BaseDirectory, Dir1) zurückgeben;" sein, oder die Methode sollte um
TheWho
16

Sie können mit meiner Bibliothek Expansive erreichen . Auch hier auf Nuget erhältlich .

Es wurde mit diesem als primären Anwendungsfall entworfen.

Moderates Beispiel (Verwenden von AppSettings als Standardquelle für die Token-Erweiterung)

In app.config:

<configuration>
    <appSettings>
        <add key="Domain" value="mycompany.com"/>
        <add key="ServerName" value="db01.{Domain}"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid=uid;pwd=pwd;Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

Verwenden Sie die Erweiterungsmethode .Expand () für die zu erweiternde Zeichenfolge:

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

oder

Verwenden Sie den Dynamic ConfigurationManager-Wrapper "Config" wie folgt (expliziter Aufruf von Expand () nicht erforderlich):

var serverName = Config.AppSettings.ServerName;
// returns "db01.mycompany.com"

var connectionString = Config.ConnectionStrings.Default;
// returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

Erweitertes Beispiel 1 (Verwenden von AppSettings als Standardquelle für die Token-Erweiterung)

In app.config:

<configuration>
    <appSettings>
        <add key="Environment" value="dev"/>
        <add key="Domain" value="mycompany.com"/>
        <add key="UserId" value="uid"/>
        <add key="Password" value="pwd"/>
        <add key="ServerName" value="db01-{Environment}.{Domain}"/>
        <add key="ReportPath" value="\\{ServerName}\SomeFileShare"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid={UserId};pwd={Password};Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

Verwenden Sie die Erweiterungsmethode .Expand () für die zu erweiternde Zeichenfolge:

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01-dev.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"
anderly
quelle
4
Ich denke diese Antwort ist sehr unterbewertet !!
Ahmad
Danke Ahmad! Lassen Sie mich wissen, wie Sie Expansive mögen.
anderly
Obwohl dies die Laufzeitauflösung der App-Einstellungen ist, werden meine Probleme mit sich wiederholenden Schlüsselwertpaaren gelöst. Wir haben damit unsere Konfigurationswartung erheblich reduziert. Die absolute Utopie hier wäre, dass dies ein Build-Time-Plugin ist, das in Verbindung mit SlowCheetah funktioniert. Ich würde wieder +1 geben, wenn ich könnte. Tolles Zeug anderly.
Ahmad
Können Sie bitte ein kurzes Beispiel geben, wie Ihre Bibliothek dazu verwendet werden könnte?
Ryan Gates
Für alle anderen, die gerade darüber stolpern, ist das Projekt seit 6 Jahren tot, seit 2011 :(
user1003916
4

Ich dachte, ich hätte gerade diese Frage gesehen.

Kurz gesagt, nein, es gibt keine variable Interpolation innerhalb einer Anwendungskonfiguration.

Sie haben zwei Möglichkeiten

  1. Sie können Ihre eigenen rollen, um Variablen zur Laufzeit zu ersetzen
  2. Massieren Sie die Anwendungskonfiguration während der Erstellung auf die Besonderheiten der Zielbereitstellungsumgebung. Einige Details dazu im Umgang mit dem Konfigurations-Albtraum
Scott Weinstein
quelle
Dies ist der richtige Beitrag. In meinem vorherigen Beitrag (dieselbe Frage) wurde das XML-Eintragsbeispiel app.config nicht angezeigt. Ich habe Ihren Link überprüft - es ist zu viel Arbeit und ich bevorzuge es, keine Zeit dort zu verbringen. Wir haben separate app.configs für verschiedene Boxen und ich möchte davon wegkommen.
DeeStackOverflow
3

Sie haben mehrere Möglichkeiten. Sie können dies mit einem Build / Deploy-Schritt tun, bei dem Ihre Konfigurationsdatei verarbeitet wird und Ihre Variablen durch den richtigen Wert ersetzt werden.

Eine andere Möglichkeit wäre, einen eigenen Konfigurationsabschnitt zu definieren, der dies unterstützt. Stellen Sie sich zum Beispiel diese XML vor:

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

Jetzt würden Sie dies mithilfe benutzerdefinierter Konfigurationsobjekte implementieren, mit denen die Variablen zur Laufzeit für Sie ersetzt werden.

JoshBerke
quelle
Ich sehe Ihre XML nicht in der Post (rücken Sie Ihre Zeile 5 Zeichen ein, um XML-Tags posten zu können - ich hatte das letzte Mal das gleiche Problem). Was sind benutzerdefinierte Konfigurationsobjekte? Ich bevorzuge eine Nullcodierung, um dies zu erreichen, da Codierungsänderungen in dieser Phase uns sehr zurückwerfen würden.
DeeStackOverflow
Benutzerdefinierte Konfiguration beinhaltet definitiv [einfache] Codierung. Aber meiner Meinung nach ist es immer die beste Option. Ich verwende fast nie appSettings und ziehe es vor, für jedes Projekt eine benutzerdefinierte Konfiguration zu erstellen.
Portman
3

Normalerweise schreibe ich eine statische Klasse mit Eigenschaften, um auf alle Einstellungen meiner web.config zuzugreifen.

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

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

}

Normalerweise schreibe ich bei Bedarf auch Konvertierungen in dieser Klasse. Es ermöglicht einen typisierten Zugriff auf Ihre Konfiguration. Wenn sich die Einstellungen ändern, können Sie sie nur an einer Stelle bearbeiten.

Normalerweise ist das Ersetzen von Einstellungen durch diese Klasse relativ einfach und bietet eine viel bessere Wartbarkeit.

Martin
quelle
3

Sie können Umgebungsvariablen in Ihrem app.configfür das von Ihnen beschriebene Szenario verwenden

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

Dann können Sie den Pfad leicht finden mit:

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

Im Inneren können <appSettings>Sie Anwendungsschlüssel erstellen,

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

Später können Sie auf diese Werte zugreifen, indem Sie:

ConfigurationManager.AppSettings["Keyname"]
Sergio
quelle
Um die ConfigurationManager-Klasse zu verwenden, müssen Sie einen Verweis auf System.Configuration hinzufügen und eine using-Anweisung für System.Configuration (Importe in VB)
hinzufügen
2
Die Angabe ist korrekt, aber keine Antwort auf die gestellte Frage.
Michaël Carpentier
1

Ich würde Ihnen DslConfig vorschlagen . Mit DslConfig können Sie hierarchische Konfigurationsdateien von Global Config, Config per Server Host verwenden, um pro Anwendung auf jedem Server Host zu konfigurieren (siehe AppSpike).
Wenn dies für Sie zu kompliziert ist, können Sie einfach die globale Konfiguration Variables.var verwenden.
Konfigurieren Sie einfach in Varibales.var

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

Und holen Sie sich die Konfigurationswerte mit

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

Ich glaube nicht, dass Sie Variablen deklarieren und verwenden können, um AppSettings-Schlüssel in einer Konfigurationsdatei zu definieren. Ich habe immer Verkettungen in Code wie Sie verwaltet.

Michaël Carpentier
quelle
0

Ich habe ein wenig Probleme mit dem, was Sie möchten, aber Sie können den App-Einstellungen eine Überschreibungsdatei hinzufügen und diese Überschreibungsdatei dann auf Umgebungsbasis festlegen.

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

Für die Einführung von Produkten, bei denen viele Elemente mit ähnlichen Werten konfiguriert werden müssen, verwenden wir kleine Konsolen-Apps, die das XML lesen und basierend auf den übergebenen Parametern aktualisieren. Diese werden dann vom Installationsprogramm aufgerufen, nachdem der Benutzer nach dem gefragt wurde Benötigte Information.

cjk
quelle
0

Ich würde empfehlen, Matt Hamsmiths Lösung zu folgen. Wenn die Implementierung ein Problem darstellt, können Sie eine Erweiterungsmethode erstellen, die dies im Hintergrund der AppSettings-Klasse implementiert.

Etwas wie:

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

    }

Innerhalb der Methode durchsuchen Sie den DictionaryInfoConfigSection mit Linq und geben den Wert mit dem passenden Schlüssel zurück. Sie müssen die Konfigurationsdatei jedoch auf folgende Weise aktualisieren:

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

Ich habe mir diese Lösung ausgedacht:

  1. In der Anwendung Settings.settings habe ich eine Variable ConfigurationBase definiert (mit type = string Scope = Application)
  2. Ich habe eine Variable in die Zielattribute in den Einstellungen eingeführt. Alle diese Attribute mussten auf Scope = User gesetzt werden
  3. In der app.xaml.cs habe ich den Wert der ConfigurationBase ausgelesen
  4. In der app.xaml.cs habe ich alle Variablen durch den ConfigurationBase-Wert ersetzt. Um die Werte zur Laufzeit zu ersetzen, mussten die Attribute auf Scopr = User gesetzt werden

Ich bin mit dieser Lösung nicht wirklich zufrieden, da ich alle Attribute manuell ändern muss. Wenn ich ein neues hinzufüge, muss ich es in der app.xaml.cs.

Hier ein Code-Snippet aus der App.xaml.cs:

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

AKTUALISIEREN

Habe gerade eine Verbesserung gefunden (wieder ein Code-Snippet aus der 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);
    }
}

Jetzt funktionieren die Ersetzungen für alle Attribute in meinen Einstellungen, die Type = string und Scope = User haben. Ich denke, ich mag es so.

UPDATE2

Anscheinend ist das Setzen von Scope = Application nicht erforderlich, wenn die Eigenschaften ausgeführt werden.

anhoppe
quelle
0

Drei mögliche Lösungen

Ich weiß, dass ich zu spät zur Party komme. Ich habe nach neuen Lösungen für das Problem der variablen Konfigurationseinstellungen gesucht. Es gibt einige Antworten, die die Lösungen berühren, die ich in der Vergangenheit verwendet habe, aber die meisten scheinen etwas verworren zu sein. Ich dachte, ich würde mir meine alten Lösungen ansehen und die Implementierungen zusammenstellen, damit sie Menschen helfen können, die mit demselben Problem zu kämpfen haben.

Für dieses Beispiel habe ich die folgende App-Einstellung in einer Konsolenanwendung verwendet:

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

1. Verwenden Sie Umgebungsvariablen

Ich glaube, die Antwort von autocro autocro hat es berührt. Ich mache nur eine Implementierung, die beim Erstellen oder Debuggen ausreichen sollte, ohne Visual Studio schließen zu müssen. Ich habe diese Lösung früher verwendet ...

  • Erstellen Sie ein Pre-Build-Ereignis, das die MSBuild-Variablen verwendet

    Warnung: Verwenden Sie eine Variable, die nicht einfach ersetzt werden kann. Verwenden Sie daher Ihren Projektnamen oder ähnliches als Variablennamen.

    SETX BaseDir "$(ProjectDir)"

  • Variablen zurücksetzen; mit etwas wie dem folgenden:

    Umgebungsvariablen beim Stapelüberlauf aktualisieren

  • Verwenden Sie die Einstellung in Ihrem Code:

'

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. Verwenden Sie die Zeichenfolgeninterpolation:

  • Verwenden Sie die Funktion 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. Verwenden einer statischen Klasse. Dies ist die Lösung, die ich am häufigsten verwende.

  • Die Umsetzung

`

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

`

  • Die statische Klasse

`

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;
        }
    }
}

`

Projektnummer:

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;
            }
        }
    }
}

Pre-Build-Ereignis:

Projekteinstellungen -> Ereignisse erstellen

StormChild
quelle