Переменные в app.config / web.config - PullRequest
82 голосов
/ 02 марта 2009

Можно ли сделать что-то подобное в файлах 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. (Я знаю, что могу управлять всей конкатенацией в коде, но я предпочитаю это так).

Ответы [ 15 ]

22 голосов
/ 02 марта 2009

Немного более сложной, но гораздо более гибкой альтернативой является создание класса, представляющего раздел конфигурации. В вашем файле 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 # в моем примере), вы можете создать два класса, таких как:

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"
14 голосов
/ 11 октября 2011

Вы можете выполнить, используя мою расширенную библиотеку: http://nuget.org/List/Packages/Expansive Источник доступен здесь: https://github.com/anderly/Expansive

7 голосов
/ 02 марта 2009

Хороший вопрос.

Я не думаю, что есть. Я считаю, что было бы достаточно хорошо известно, если бы существовал простой способ, и я вижу, что 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>
4 голосов
/ 02 марта 2009

Я думал, что только что увидел этот вопрос.

Короче говоря, нет, в конфигурации приложения нет интерполяции переменных.

У вас есть два варианта

  1. Вы можете свернуть свои собственные переменные для замены во время выполнения
  2. Во время сборки сконфигурируйте конфигурацию приложения в соответствии с конкретными особенностями целевой среды развертывания. Некоторые подробности об этом на , касающиеся конфигурации-кошмара
3 голосов
/ 02 марта 2009

Обычно я в конечном итоге пишу статический класс со свойствами для доступа к каждому из параметров моего 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 голосов
/ 02 марта 2009

У вас есть несколько вариантов. Вы можете сделать это с помощью шага сборки / развертывания, который обработает ваш файл конфигурации и заменит ваши переменные на правильное значение.

Другой вариант - определить свой собственный раздел конфигурации, который поддерживает это. Например, представьте это xml:

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

Теперь вы реализуете это, используя настраиваемые объекты конфигурации, которые будут обрабатывать замену переменных для вас во время выполнения.

2 голосов
/ 25 ноября 2015

Вы можете использовать переменные среды в вашем app.config для того сценария, который вы описываете

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

Тогда вы можете легко получить путь с помощью:

var pathFromConfig = ConfigurationManager.AppSettings["Dir1"];
var expandedPath = Environment.ExpandEnvironmentVariables(pathFromConfig);
1 голос
/ 10 февраля 2012

Я бы предложил вам DslConfig . С DslConfig вы можете использовать иерархические конфигурационные файлы из Global Config, 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 голос
/ 02 марта 2009

Внутри <appSettings> вы можете создавать ключи приложений,

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

Позже вы можете получить доступ к этим значениям, используя:

ConfigurationManager.AppSettings["Keyname"]
0 голосов
/ 12 августа 2017

Три возможных решения

Я знаю, что опаздываю на вечеринку, я искал, есть ли какие-нибудь новые решения проблемы с переменными параметрами конфигурации. Есть несколько ответов, которые касаются решений, которые я использовал в прошлом, но большинство кажется немного запутанными. Я подумал, что посмотрю на мои старые решения и соберу реализации, чтобы они могли помочь людям, которые борются с той же проблемой.

Для этого примера я использовал следующие настройки приложения в консольном приложении:

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

1. Используйте переменные окружения

Я считаю, что autocro ответ autocro затронул его. Я просто делаю реализацию, которой должно хватить при сборке или отладке без необходимости закрывать визуальную студию. Я использовал это решение еще в тот день ...

  • Создать событие перед сборкой, которое будет использовать переменные 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;
            }
        }
    }
}

Событие перед сборкой:

Настройки проекта -> События сборки

...