Pregunta

¿Es posible hacer algo como lo siguiente en los archivos app.config o web.config?

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

Entonces quiero acceder a Dir2 en mi código simplemente diciendo:

 ConfigurationManager.AppSettings["Dir2"]

Esto me ayudará cuando instale mi aplicación en diferentes servidores y ubicaciones en las que solo tendré que cambiar UNA entrada en toda mi <=>. (Sé que puedo administrar toda la concatenación en código, pero lo prefiero de esta manera).

¿Fue útil?

Solución

Buena pregunta.

No creo que haya. Creo que habría sido bastante conocido si hubiera una manera fácil, y veo que Microsoft está creando un mecanismo en Visual Studio 2010 para implementar diferentes archivos de configuración para su implementación y prueba.

Dicho esto, sin embargo; Descubrí que en la sección ConnectionStrings tiene un tipo de marcador de posición llamado & Quot; | DataDirectory | & Quot ;. Tal vez podrías echar un vistazo a lo que está funcionando allí ...

Aquí hay una pieza de machine.config que lo muestra:

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

Otros consejos

Una alternativa un poco más complicada, pero mucho más flexible, es crear una clase que represente una sección de configuración. En su archivo app.config / web.config, puede tener esto:

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

Luego, en su código .NET (usaré C # en mi ejemplo), puede crear dos clases como esta:

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

Finalmente, en su código de programa, puede acceder a sus <=> variables, usando sus nuevas clases, de esta manera:

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

Puede lograrlo usando mi biblioteca expansiva: http://nuget.org/List/Packages/Expansive La fuente está disponible aquí: https://github.com/anderly/Expansive

Pensé que acababa de ver esta pregunta.

En resumen, no, no hay interpolación variable dentro de la configuración de una aplicación.

Tienes dos opciones

  1. Podrías rodar el tuyo para sustituir variables en tiempo de ejecución
  2. En el momento de la compilación, aplique la configuración de la aplicación a los detalles específicos del entorno de implementación de destino. Algunos detalles sobre esto en trato con la pesadilla de configuración

Tienes un par de opciones. Puede hacer esto con un paso de compilación / implementación que procesaría su archivo de configuración reemplazando sus variables con el valor correcto.

Otra opción sería definir su propia sección de Configuración que lo respaldara. Por ejemplo, imagine este xml:

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

Ahora implementaría esto utilizando objetos de configuración personalizados que manejarían el reemplazo de las variables por usted en tiempo de ejecución.

Normalmente, termino escribiendo una clase estática con propiedades para acceder a cada una de las configuraciones de mi 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();
    }

}

Por lo general, también escribo conversiones cuando es necesario en esta clase. Permite tener un acceso escrito a su configuración, y si la configuración cambia, puede editarla en un solo lugar.

Por lo general, reemplazar la configuración con esta clase es relativamente fácil y proporciona una capacidad de mantenimiento mucho mayor.

Puede usar variables de entorno en su app.config para el escenario que describe

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

Entonces puede obtener fácilmente la ruta con:

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

Dentro de <appSettings> puede crear claves de aplicación,

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

Más adelante puede acceder a estos valores usando:

ConfigurationManager.AppSettings["Keyname"]

Te sugeriría DslConfig . Con DslConfig puede usar archivos de configuración jerárquicos de Global Config, Config por servidor host para configurar por aplicación en cada servidor host (vea AppSpike).
Si esto es demasiado complicado para usted, puede usar la configuración global Variables.var
Simplemente configure en Varibales.var

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

Y obtenga los valores de configuración con

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

No creo que pueda declarar y usar variables para definir claves de configuración de aplicaciones dentro de un archivo de configuración. Siempre he administrado concatenaciones en código como usted.

Estoy luchando un poco con lo que quieres, pero puedes agregar un archivo de anulación a la configuración de la aplicación y luego configurar ese archivo de anulación en función del entorno.

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

Para implementar productos en los que necesitamos configurar una gran cantidad de elementos con valores similares, utilizamos pequeñas aplicaciones de consola que leen el XML y se actualizan en función de los parámetros pasados. Luego, el instalador los invoca después de haber solicitado usuario para la información requerida.

Recomendaría seguir la solución de Matt Hamsmith. Si es un problema implementar, ¿por qué no crear un método de extensión que implemente esto en segundo plano en la clase AppSettings?

Algo así como:

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

    }

Dentro del método que busca a través de DictionaryInfoConfigSection usando Linq y devuelve el valor con la clave correspondiente. Sin embargo, necesitará actualizar el archivo de configuración, en algo como esto:

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

Se me ocurrió esta solución:

  1. En la aplicación Settings.settings definí una variable ConfigurationBase (con type = string Scope = Application)
  2. Introduje una variable en los atributos de destino en Settings.settings, todos esos atributos tuvieron que establecerse en Scope = User
  3. En la app.xaml.cs leí el valor de ConfigurationBase
  4. En la app.xaml.cs, reemplacé todas las variables con el valor de ConfigurationBase. Para reemplazar los valores en tiempo de ejecución, los atributos tuvieron que establecerse en Scopr = Usuario

No estoy muy contento con esta solución porque tengo que cambiar todos los atributos manualmente, si agrego uno nuevo tengo que considerarlo en la app.xaml.cs.

Aquí un fragmento de código de App.xaml.cs:

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

UPDATE

Acabo de encontrar una mejora (de nuevo un fragmento de código de la aplicación.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);
    }
}

Ahora los reemplazos funcionan para todos los atributos en mi configuración que tienen Type = string y Scope = User. Creo que me gusta de esta manera.

UPDATE2

Aparentemente, configurar Scope = La aplicación no es necesaria cuando se ejecuta sobre las propiedades.

Tres posibles soluciones

  

Sé que llego tarde a la fiesta, he estado buscando si había nuevas soluciones al problema de configuración de configuración variable. Hay algunas respuestas que tocan las soluciones que he usado en el pasado, pero la mayoría parece un poco complicada. Pensé que miraría mis viejas soluciones y uniría las implementaciones para ayudar a las personas que están luchando con el mismo problema.

Para este ejemplo, he utilizado la siguiente configuración de aplicación en una aplicación de consola:

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

1. Usar variables de entorno

  

Creo que autocro respuesta de autocro lo tocó. Solo estoy haciendo una implementación que debería ser suficiente al construir o depurar sin tener que cerrar Visual Studio. He usado esta solución en el pasado ...

  • Cree un evento previo a la compilación que utilizará las variables MSBuild

      

    Advertencia: use una variable que no se pueda reemplazar fácilmente, así que use el nombre de su proyecto o algo similar como un nombre de variable.

    SETX BaseDir "$(ProjectDir)"

  • Restablecer variables; usando algo como lo siguiente:

    Actualizar variables de entorno en desbordamiento de pila

  • Use la configuración en su código:

'

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. Utilice la interpolación de cadenas:

  • Use la función 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. Usando una clase estática, esta es la solución que uso principalmente.

  • La implementación

`

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

`

  • La clase estática

`

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

`

Código de proyecto:

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 previo a la compilación:

Configuración del proyecto - > Crear eventos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top