Переменные в приложении.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 ответов:
хороший вопрос.
Я не думаю, что есть. Я считаю, что было бы неплохо знать, если есть простой способ, и я вижу, что 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
Я думал, что только что видел этот вопрос.
короче говоря, нет, нет переменной интерполяции в конфигурации приложения.
У вас есть два варианта
- вы можете свернуть свой собственный, чтобы заменить переменные во время выполнения
- во время сборки выполните массаж конфигурации приложения в соответствии с конкретными особенностями целевой среды развертывания. Некоторые подробности об этом на работа с конфигурация-кошмар
у вас есть несколько вариантов. Вы можете сделать это с помощью шага сборки / развертывания, который будет обрабатывать ваш файл конфигурации, заменяя ваши переменные правильным значением.
другой вариант - определить свой собственный раздел конфигурации, который поддерживает это. Например, представьте себе этот 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"]
Я придумал такое решение:
- в настройках приложения.настройки я определил переменную ConfigurationBase (с типом=string Scope=Application)
- я ввел переменную в целевые атрибуты в настройках.настройки, все эти атрибуты должны были быть установлены в Scope=User
- в приложение.код XAML.cs я считываю значение, если ConfigurationBase
- в приложение.код 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>