Вопрос

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

Это было полезно?

Решение

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

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

Затем в вашем .СЕТЕВОМ коде (я буду использовать 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>

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

Обычно я заканчиваю тем, что пишу статический класс со свойствами для доступа к каждому из параметров моего 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();
    }

}

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

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

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

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

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

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

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

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

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

ConfigurationManager.AppSettings["Keyname"]

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

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

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

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

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

Вот фрагмент кода из App.xaml.cs:

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

Обновить

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

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

  • Используйте функцию 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 - Программа.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;
            }
        }
    }
}

Событие предварительной сборки:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top