Подтвердить что ты не робот

Переменные в app.config/web.config

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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 Dir1 {
            get {
                return (String)base["Dir1"];
            }
        }

        [ConfigurationProperty("Dir2")]
        public String Dir2 {
            get {
                return (String)base["Dir2"];
            }
        }
        // You can make custom properties to combine your directory names.
        public String Dir1Resolved {
            get {
                return System.IO.Path.Combine(MyBaseDir, Dir1);
            }
        }
    }
}

Наконец, в вашем программном коде вы можете получить доступ к своим переменным app.config, используя ваши новые классы следующим образом:

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

Ответ 4

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

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

У вас есть две опции

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

Ответ 5

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

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

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

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

Ответ 6

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

}

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

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

Ответ 7

Я предлагаю вам 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")

Ответ 8

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

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

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

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

Ответ 9

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

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

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

ConfigurationManager.AppSettings["Keyname"]

Ответ 10

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

Я бы порекомендовал вам решение Matt Hamsmith. Если это проблема для реализации, то почему бы не создать метод расширения, который реализует это в фоновом режиме в классе 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>

Ответ 14

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

  • В приложении Settings.settings я определил переменную ConfigurationBase (с типом = строка Scope = Application)
  • Я представил переменную в целевых атрибутах в настройках Settings.settings, все эти атрибуты должны были быть установлены в Scope = User
  • В app.xaml.cs я считываю значение, если ConfigurationBase
  • В 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);

UPDATE

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

UPDATE2

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

Ответ 15

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

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

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

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

  • Reset переменные; используя что-то вроде следующего:

    Обновить переменные среды при переполнении стека

  • Используйте настройку в своем коде:

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

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

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