Переменные в приложении.config / web.конфиг


можно ли сделать что-то вроде следующего в 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 79

15 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

Как правило, замена настроек на этот класс относительно проста и обеспечивает гораздо большую ремонтопригодность.

Я бы предложил вам DslConfig. С помощью DslConfig вы можете использовать иерархические файлы конфигурации из Global Config, Config для каждого хоста сервера в config для каждого приложения на каждом хосте сервера (см. AppSpike).
Если это сложно для вас, вы можете просто использовать глобальные переменные конфига.ВАР
Просто настроить в Varibales.ВАР

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

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

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

затем вы можете легко получить путь с:

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

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

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

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

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

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

что-то типа:

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

    }

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

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

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

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

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

ConfigurationManager.AppSettings["Keyname"]

Я придумал такое решение:

  1. в настройках приложения.настройки я определил переменную ConfigurationBase (с типом=string Scope=Application)
  2. я ввел переменную в целевые атрибуты в настройках.настройки, все эти атрибуты должны были быть установлены в Scope=User
  3. в приложение.код XAML.cs я считываю значение, если ConfigurationBase
  4. в приложение.код XAML.cs Я заменил все переменные значением ConfigurationBase. В чтобы заменить значения во время выполнения, атрибуты должны были быть установлены в Scopr=User

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

вот фрагмент кода из приложения.код XAML.cs:

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

обновление

только что нашел улучшение (снова фрагмент кода из приложения.код 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);
    }
}

теперь замены работают для всех атрибутов в моих настройках, которые имеют Type=string и Scope=User. Думаю, мне это нравится.

обновление 2

по-видимому, установка Scope=Application не требуется при запуске свойств.

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

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

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

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

1. Используйте переменные среды

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

  • создайте событие предварительной сборки, которое будет использовать 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. Используйте строковую интерполяцию:

  • использовать строку.Формат () функция

'

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

'

Код Проекта:

приложение.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>