Pergunta

É possível fazer algo como o seguinte nos arquivos app.config ou web.config?

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

Eu, então, deseja acessar Dir2 no meu código, simplesmente dizendo:

 ConfigurationManager.AppSettings["Dir2"]

Isso vai me ajudar quando eu instalar a minha aplicação em diferentes servidores e os locais onde eu só vai ter que mudar uma entrada em toda a minha app.config. (Eu sei que posso gerir toda a concatenação no código, mas eu prefiro assim).

Foi útil?

Solução

Boa pergunta.

Eu não acho que há. Acredito que teria sido bastante conhecido se não havia uma maneira fácil, e vejo que a Microsoft está criando um mecanismo no Visual Studio 2010 para a implantação de diferentes arquivos de configuração para implantação e teste.

Com o que disse, no entanto; Eu descobri que você na seção ConnectionStrings têm uma espécie de espaço reservado chamado de "| DataDirectory |". Talvez você possa ter um olhar para o que está no trabalho lá ...

Aqui está um pedaço de machine.config mostrá-lo:

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

Outras dicas

Um pouco mais complicado, mas muito mais flexível, alternativa é criar uma classe que representa uma seção de configuração. Em seu arquivo app.config / web.config, você pode ter o seguinte:

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

Então, em seu código NET (vou usar C # no meu exemplo), você pode criar duas classes como este:

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, em seu código de programa, você pode acessar suas variáveis ??app.config, usando suas novas classes, da seguinte maneira:

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

Você pode fazer usando minha biblioteca expansiva: http://nuget.org/List/Packages/Expansive Fonte está disponível aqui: https://github.com/anderly/Expansive

Eu pensei que eu só vi esta questão.

Em suma, não, não há nenhuma interpolação variável dentro de uma configuração de aplicação.

Você tem duas opções

  1. Você poderia rolar seus próprios com as variáveis ??de substituição em tempo de execução
  2. em tempo de compilação, massagear a configuração da aplicação às especificidades particulares do ambiente de implantação de destino. Alguns detalhes sobre este em que lidam com a configuração de pesadelo

Você tem um par de opções. Você poderia fazer isso com uma etapa de compilação / deploy que iria processar seu arquivo de configuração substituindo suas variáveis ??com o valor correto.

Outra opção seria a de definir a sua própria seção de configuração, que apoiou esta. Por exemplo, imagine este xml:

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

Agora você poderia implementar isso usando objetos de configuração personalizada que iria lidar com substituindo as variáveis ??para você em tempo de execução.

Usally, acabo escrevendo uma classe estática com propriedades para acessar cada uma das configurações do meu 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();
    }

}

Normalmente, eu também fazer conversões tipo, quando necessários nesta classe. Ele permite ter um acesso digitado a sua configuração, e se alterar as configurações, você pode editá-los em um só lugar.

Normalmente, substituindo as definições com esta classe é relativamente fácil e proporciona uma maior capacidade de manutenção muito.

Você pode usar variáveis ??de ambiente em sua app.config para esse cenário que você descrever

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

Em seguida, você pode facilmente obter o caminho com:

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

Dentro <appSettings> você pode criar teclas de aplicação,

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

Mais tarde, você pode acessar esses valores usando:

ConfigurationManager.AppSettings["Keyname"]

Eu sugiro que você DslConfig . Com DslConfig você pode usar arquivos de configuração hierárquica da Global Config, configuração por host servidor de configuração por aplicação em cada host do servidor (veja o AppSpike).
Se esta é a complicado para você, você pode simplesmente usar a configuração global Variables.var
configure apenas no Varibales.var

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

e obter os valores de configuração com

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

Eu não acho que você pode declarar e usar variáveis ??para definir as chaves appSettings dentro de um arquivo de configuração. Eu sempre conseguiu concatenations no código como você.

Eu estou lutando um pouco com o que você quer, mas você pode adicionar um arquivo de substituição para as configurações de aplicativos, em seguida, ter esse conjunto de arquivos override em uma base por meio ambiente.

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

Para lançando produtos em que temos de configurar um monte de itens com valores semelhantes, usamos pequenas aplicações de console que ler o XML e atualização com base nos parâmetros passados. Estes são então chamados pelo instalador após ele pediu ao usuário para as informações necessárias.

Eu recomendaria seguinte solução de Matt Hamsmith. Se é uma questão de implementar, em seguida, por que não criar um método de extensão que implementa essa no fundo da classe AppSettings?

Algo como:

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

    }

Dentro do método que você pesquisar através da DictionaryInfoConfigSection usando Linq e retornar o valor com a chave correspondente. Você precisará atualizar o arquivo de configuração, porém, para algo ao longo destas linhas:

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

Eu vim com essa solução:

  1. Na aplicação Settings.settings I definida uma variável ConfigurationBase (com type = cadeia Âmbito = Aplicação)
  2. I introduziu uma variável nos atributos alvo nos Settings.settings, todos esses atributos teve que ser ajustado para Scope = Usuário
  3. Nos App.xaml.cs eu li o valor se o ConfigurationBase
  4. Nos App.xaml.cs Troquei todas as variáveis ??com o valor ConfigurationBase. A fim de substituir os valores em tempo de execução os atributos teve que ser ajustado para Scopr = Usuário

Eu não estou realmente feliz com esta solução, porque eu tenho que mudar todos os atributos manualmente, se eu adicionar um novo eu tenho que considerá-la nas App.xaml.cs.

Aqui um trecho de código a partir dos App.xaml.cs:

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

Atualizar

Só encontrei uma melhoria (novamente um trecho de código a partir dos 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);
    }
}

Agora, as substituições de trabalho para todos os atributos em minhas configurações que têm Type = corda e Scope = usuário. Eu acho que eu gosto desta forma.

UPDATE2

ajuste Aparentemente Scope = Aplicação não é necessária quando correndo sobre as propriedades.

três soluções possíveis

Eu sei que estou chegando atrasado para a festa, eu estive procurando se havia novas soluções para o problema da configuração variável configurações. Há algumas respostas que tocam as soluções que tenho usado no passado, mas a maioria parece um pouco complicado. Eu pensei que eu ia olhar para as minhas velhas soluções e colocar as implementações em conjunto de modo que ele pode ajudar as pessoas que estão lutando com o mesmo problema.

Para este exemplo eu usei a seguinte configuração aplicativo em um aplicativo de console:

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

1. Usar variáveis ??de ambiente

Acredito que autocro de autocro resposta tocou nele. Eu estou apenas fazendo uma implementação que deve ser suficiente na construção ou depuração sem ter que visual studio perto. Eu tenho usado essa solução de volta ao dia ...

  • Criar um evento de pré-compilação que vai usar as variáveis ??MSBuild

    Atenção:. Use uma variável que não será substituído facilmente, então usar seu nome de projeto ou algo semelhante como um nome de variável

    SETX BaseDir "$(ProjectDir)"

  • variáveis ??Repor; usando algo como o seguinte:

    Atualizar meio ambiente no Stack Overflow

  • Use a configuração no seu 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. Use interpolação de string:

  • Use o string.Format () function

`

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 uma classe estática, esta é a solução que eu uso principalmente.

  • A implementação

`

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

`

  • A classe 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 do projeto:

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 pré-compilação:

Project Settings -> Build Events

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top