Variabili all'interno di app.config / web.config


92

È possibile fare qualcosa di simile nei file app.configo web.config?

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

Quindi voglio accedere a Dir2 nel mio codice semplicemente dicendo:

 ConfigurationManager.AppSettings["Dir2"]

Questo mi aiuterà quando installo la mia applicazione in diversi server e posizioni in cui dovrò cambiare solo UNA voce nel mio intero app.config. (So ​​di poter gestire tutta la concatenazione in codice, ma preferisco così).


Penso che stia parlando della definizione delle variabili da utilizzare nelle chiavi appSettings direttamente all'interno dei file di configurazione.
Michaël Carpentier

1
Ho anche verificato utilizzando la dichiarazione XML <! ENTITY>, ma non è supportata a causa del modo in cui MS gestisce i file web.config.
chilltemp

Grazie per il tuo impegno. Preferisco non modificare alcun codice. Il codice ha già un'istruzione che dice: string dir2 = ConfigurationManager.AppSettings ["Dir2"]. Voglio solo pulire l'app.config che ora dice value = "D: \ blahdir \ Dir2" invece di value = "[MyBaseDir] \
Dir2

Risposte:


7

Buona domanda.

Non credo che ci sia. Credo che sarebbe stato abbastanza noto se ci fosse un modo semplice e vedo che Microsoft sta creando un meccanismo in Visual Studio 2010 per distribuire diversi file di configurazione per la distribuzione e il test.

Detto questo, tuttavia; Ho scoperto che nella ConnectionStringssezione hai una specie di segnaposto chiamato "| DataDirectory |". Forse potresti dare un'occhiata a cosa c'è al lavoro lì ...

Ecco un pezzo da machine.configmostrarlo:

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

Questa è un'informazione interessante. Forse si accede alle variabili utilizzando il simbolo pipe ("|")? Hmm .. Mi chiedo se funzionerà: <add key = "Dir2" value = "| MyBaseDir | \ Dir2" />
DeeStackOverflow

4
Il valore DataDirectory è in realtà un elemento dati in AppDomain. È possibile sostituire il valore utilizzando AppDomain.CurrentDomain.SetData ("DataDirectory", dataPath); Non ho verificato se puoi definire altre variabili come questa e farle "autoespandere" però ...
Peter Lillevold

22

Un'alternativa leggermente più complicata, ma molto più flessibile, è creare una classe che rappresenti una sezione di configurazione. Nel tuo file app.config/ web.config, puoi avere questo:

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

Quindi, nel tuo codice .NET (userò C # nel mio esempio), puoi creare due classi come questa:

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

Infine, nel codice del tuo programma, puoi accedere alle tue app.configvariabili, usando le tue nuove classi, in questo modo:

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

1
Grazie ma sto cercando di farlo senza modificare alcun codice in quanto è un problema in questa fase.
DeeStackOverflow

C'è un piccolo errore nell'ultima riga di codice (senza contare le parentesi graffe): "return System.IO.Path.Combine (MyBaseDir, Dir1);" dovrebbe invece essere "return System.IO.Path.Combine (BaseDirectory, Dir1);", altrimenti il ​​metodo dovrebbe essere rinominato da 'Base Directory' a 'MyBaseDir'
TheWho

16

Puoi realizzare usando la mia libreria espansiva . Disponibile anche su nuget qui .

È stato progettato con questo come caso d'uso principale.

Esempio moderato (utilizzando AppSettings come origine predefinita per l'espansione del token)

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>

Usa il metodo di estensione .Expand () sulla stringa da espandere:

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

o

Utilizza il wrapper Dynamic ConfigurationManager "Config" come segue (chiamata esplicita a Expand () non necessaria):

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

Esempio avanzato 1 (utilizzando AppSettings come origine predefinita per l'espansione del token)

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>

Usa il metodo di estensione .Expand () sulla stringa da espandere:

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

4
Penso che questa risposta sia molto sottovalutata !!
Ahmad

Grazie Ahmad! Fammi sapere se ti piace Expansive.
anderly

Sebbene questa sia la "risoluzione" di runtime delle impostazioni dell'app, risolve i miei problemi di avere coppie di valori chiave ripetitive. Abbiamo ridotto in modo significativo la manutenzione della nostra configurazione utilizzando questo. L'utopia assoluta qui sarebbe quella di avere questo plug-in in fase di compilazione che funzioni in combinazione con SlowCheetah. Farei di nuovo +1 se potessi. Grandi cose anderly.
Ahmad

Puoi fornire un breve esempio di come la tua libreria potrebbe essere utilizzata per ottenere questo risultato?
Ryan Gates

Per chiunque altro si sia imbattuto in questo, il progetto è morto da 6 anni, dal 2011 :(
user1003916

4

Pensavo di aver appena visto questa domanda.

In breve, no, non c'è interpolazione di variabili all'interno di una configurazione dell'applicazione.

Hai due opzioni

  1. Potresti lanciarne uno tuo per sostituire le variabili in fase di esecuzione
  2. In fase di compilazione, adattare la configurazione dell'applicazione alle specifiche specifiche dell'ambiente di distribuzione di destinazione. Alcuni dettagli su questo aspetto nell'affrontare l'incubo della configurazione

Questo è il post corretto. Il mio post precedente (stessa domanda) non mostrava l'esempio di voce xml app.config. Ho controllato il tuo link: è troppo lavoro e preferisco non passare il tempo lì. Abbiamo app.configs separati per scatole diverse e voglio allontanarmi da quello.
DeeStackOverflow

3

Hai un paio di opzioni. È possibile farlo con una fase di creazione / distribuzione che elaborerebbe il file di configurazione sostituendo le variabili con il valore corretto.

Un'altra opzione potrebbe essere quella di definire la propria sezione Configurazione che lo supporta. Ad esempio, immagina questo xml:

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

Ora dovresti implementarlo utilizzando oggetti di configurazione personalizzati che gestiranno la sostituzione delle variabili per te in fase di esecuzione.


Non vedo il tuo xml nel post (rientra i caratteri della riga 5 per poter pubblicare tag xml - ho avuto lo stesso problema l'ultima volta). Inoltre, cosa sono gli "oggetti di configurazione personalizzati"? Preferisco la codifica zero per ottenere questo risultato poiché le modifiche alla codifica in questa fase ci farebbero tornare indietro molto.
DeeStackOverflow

La configurazione personalizzata implica sicuramente una codifica [semplice]. Ma IMHO è sempre la tua migliore opzione. Non uso quasi mai appSettings, preferisco invece creare una configurazione personalizzata per ogni progetto.
Portman

3

Di solito, finisco per scrivere una classe statica con proprietà per accedere a ciascuna delle impostazioni del mio 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();
    }

}

Di solito, faccio anche conversioni di tipo quando richiesto in questa classe. Permette di avere un accesso digitato alla tua configurazione e, se le impostazioni cambiano, puoi modificarle in un solo posto.

Di solito, la sostituzione delle impostazioni con questa classe è relativamente facile e fornisce una maggiore manutenibilità.


3

Puoi usare le variabili d'ambiente nel tuo app.configper quello scenario che descrivi

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

Quindi puoi facilmente ottenere il percorso con:

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

2

All'interno <appSettings>puoi creare chiavi dell'applicazione,

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

Successivamente potrai accedere a questi valori utilizzando:

ConfigurationManager.AppSettings["Keyname"]

Per utilizzare la classe ConfigurationManager è necessario aggiungere un riferimento a System.Configuration e aggiungere un'istruzione using per System.Configuration (importazioni in VB)
cjk

2
L'indicazione è corretta ma non è una risposta alla domanda posta.
Michaël Carpentier

1

Ti suggerirei DslConfig . Con DslConfig puoi utilizzare file di configurazione gerarchici da Global Config, Config per host server per configurare per applicazione su ogni host server (vedi AppSpike).
Se questo è troppo complicato per te puoi semplicemente usare la configurazione globale Variables.var
Configura semplicemente in Varibales.var

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

E ottieni i valori di configurazione con

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

0

Non penso che tu possa dichiarare e utilizzare variabili per definire le chiavi appSettings all'interno di un file di configurazione. Ho sempre gestito concatenazioni in codice come te.


0

Sto lottando un po 'con quello che vuoi, ma puoi aggiungere un file di sostituzione alle impostazioni dell'app, quindi impostare il file di sostituzione in base all'ambiente.

<appSettings file="..\OverrideSettings.config">

0

Per la distribuzione di prodotti in cui è necessario configurare molti elementi con valori simili, utilizziamo piccole app console che leggono l'XML e si aggiornano in base ai parametri passati. Queste vengono quindi chiamate dall'installatore dopo che ha chiesto all'utente il informazioni richieste.


0

Consiglierei di seguire la soluzione di Matt Hamsmith. Se è un problema da implementare, perché non creare un metodo di estensione che lo implementi in background nella classe AppSettings?

Qualcosa di simile a:

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

    }

All'interno del metodo si cerca in DictionaryInfoConfigSection utilizzando Linq e si restituisce il valore con la chiave corrispondente. Tuttavia, dovrai aggiornare il file di configurazione a qualcosa del genere:

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

0

Ho trovato questa soluzione:

  1. Nell'applicazione Settings.settings ho definito una variabile ConfigurationBase (con type = string Scope = Application)
  2. Ho introdotto una variabile negli attributi di destinazione in Settings.settings, tutti quegli attributi dovevano essere impostati su Scope = User
  3. In app.xaml.cs ho letto il valore se il file ConfigurationBase
  4. In app.xaml.cs ho sostituito tutte le variabili con il valore ConfigurationBase. Per sostituire i valori in fase di esecuzione, gli attributi dovevano essere impostati su Scopr = User

Non sono molto soddisfatto di questa soluzione perché devo modificare tutti gli attributi manualmente, se ne aggiungo uno nuovo devo considerarlo nell'app.xaml.cs.

Di seguito uno snippet di codice da App.xaml.cs:

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

AGGIORNARE

Ho appena trovato un miglioramento (di nuovo uno snippet di codice da 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);
    }
}

Ora le sostituzioni funzionano per tutti gli attributi nelle mie impostazioni che hanno Type = string e Scope = User. Penso che mi piaccia in questo modo.

AGGIORNAMENTO 2

Apparentemente l'impostazione Scope = Application non è richiesta quando si esegue sopra le proprietà.


0

Tre possibili soluzioni

So che arrivo in ritardo alla festa, ho cercato se c'erano nuove soluzioni al problema delle impostazioni di configurazione delle variabili. Ci sono alcune risposte che toccano le soluzioni che ho usato in passato, ma la maggior parte sembra un po 'contorta. Ho pensato di esaminare le mie vecchie soluzioni e mettere insieme le implementazioni in modo che potesse aiutare le persone che stanno lottando con lo stesso problema.

Per questo esempio ho utilizzato la seguente impostazione dell'app in un'applicazione console:

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

1. Usa le variabili d'ambiente

Credo che la risposta di autocro di autocro l'abbia toccata. Sto solo eseguendo un'implementazione che dovrebbe essere sufficiente durante la creazione o il debug senza dover chiudere Visual Studio. Ho usato questa soluzione nel corso della giornata ...

  • Crea un evento di pre-compilazione che utilizzerà le variabili di MSBuild

    Avvertenza: utilizza una variabile che non verrà sostituita facilmente, quindi utilizza il nome del progetto o qualcosa di simile come nome della variabile.

    SETX BaseDir "$(ProjectDir)"

  • Resetta le variabili; usando qualcosa di simile al seguente:

    Aggiorna le variabili d'ambiente in Stack Overflow

  • Usa l'impostazione nel tuo codice:

'

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. Usa l'interpolazione di stringhe:

  • Usa la funzione 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. Utilizzando una classe statica, questa è la soluzione che uso maggiormente.

  • L'implemento

"

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

"

  • La classe statica

"

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

"

Codice del progetto:

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

Evento pre-costruzione:

Impostazioni progetto -> Eventi build

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.