app.config / web.config中的变量


92

是否可以在app.configweb.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。(我知道我可以在代码中管理所有串联,但是我更喜欢这种方式)。


我认为他是在谈论定义要在配置文件中直接在appSettings键中使用的变量。
迈克尔卡彭铁尔

1
我还使用XML <!ENTITY>声明签出,但由于MS处理web.config文件的方式而不受支持。
chilltemp

感谢您的努力。我宁愿不修改任何代码。该代码已经有一条语句:string dir2 = ConfigurationManager.AppSettings [“ Dir2”]。我只想清理app.config,现在说value =“ D:\ blahdir \ Dir2”而不是value =“ [MyBaseDir] \ Dir2”
DeeStackOverflow 2009年

Answers:


7

好问题。

我认为没有。我相信,如果有一种简便的方法,这将是众所周知的,并且我看到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>

那是有趣的信息。也许使用管道符号(“ |”)访问变量?嗯..我不知道这是否行得通:<add key =“ Dir2” value =“ | MyBaseDir | \ Dir2” />
DeeStackOverflow

4
DataDirectory值实际上是AppDomain中的数据元素。您可以使用AppDomain.CurrentDomain.SetData(“ DataDirectory”,dataPath);覆盖该值。我还没有测试过是否可以定义其他变量,并使它们“自动
扩展

22

一个稍微复杂但灵活得多的替代方法是创建一个代表配置节的类。在您的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"

1
谢谢,但是我试图在不修改任何代码的情况下执行此操作,因为在此阶段这很痛苦。
DeeStackOverflow

代码的最后一行有一个小错误(不计算括号):“返回System.IO.Path.Combine(MyBaseDir,Dir1);” 应该改为“返回System.IO.Path.Combine(BaseDirectory,Dir1);”,否则该方法应从“基本目录”重命名为“ MyBaseDir”
TheWho

16

您可以使用我的库Expansive来完成。也可以在nuget上找到

它是以此设计为主要用例的。

中等示例(使用AppSettings作为令牌扩展的默认来源)

在app.config中:

<configuration>
    <appSettings>
        <add key="Domain" value="mycompany.com"/>
        <add key="ServerName" value="db01.{Domain}"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid=uid;pwd=pwd;Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

扩展的字符串上使用.Expand()扩展方法:

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

要么

如下使用Dynamic ConfigurationManager包装器“ Config”(无需显式调用Expand()):

var serverName = Config.AppSettings.ServerName;
// returns "db01.mycompany.com"

var connectionString = Config.ConnectionStrings.Default;
// returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

高级示例1(使用AppSettings作为令牌扩展的默认源)

在app.config中:

<configuration>
    <appSettings>
        <add key="Environment" value="dev"/>
        <add key="Domain" value="mycompany.com"/>
        <add key="UserId" value="uid"/>
        <add key="Password" value="pwd"/>
        <add key="ServerName" value="db01-{Environment}.{Domain}"/>
        <add key="ReportPath" value="\\{ServerName}\SomeFileShare"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid={UserId};pwd={Password};Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

在要扩展的字符串上使用.Expand()扩展方法:

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01-dev.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

4
我认为这个答案是非常低估!
艾哈迈德

谢谢艾哈迈德!让我知道您如何喜欢Expansive。
2013年

尽管这是应用程序设置的运行时“解析”,但它解决了我拥有重复键值对的问题。使用此工具,我们已大大减少了配置维护。这里的绝对乌托邦是将其作为一个构建时插件与SlowCheetah结合使用。如果可以的话,我会再次+1。好东西。
艾哈迈德(Ahmad)2013年

您能否提供一个简短的示例说明如何使用您的库来完成此任务?
瑞安·盖茨

对于刚刚在此绊脚石的其他人,该项目自2011年以来已经死了6年:(
user1003916

4

我以为我刚刚看到了这个问题。

简而言之,没有,在应用程序配置中没有变量插值。

你有两个选择

  1. 您可以在运行时自行滚动以替换变量
  2. 在构建时,将应用程序配置调整为目标部署环境的特定细节。处理配置噩梦的一些细节

这是正确的帖子。我以前的帖子(相同的问题)没有显示app.config xml条目示例。我检查了您的链接-太多的工作,不想在那儿花时间。我们为不同的盒子提供了单独的app.configs,我想摆脱它。
DeeStackOverflow

3

您有两种选择。您可以通过构建/部署步骤来执行此操作,该步骤将处理您的配置文件,以正确的值替换变量。

另一个选择是定义自己的“配置”部分以支持此设置。例如,假设此xml:

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

现在,您将使用自定义配置对象来实现此目的,该对象将在运行时为您替换变量。


我在帖子中看不到您的xml(缩进您的第5行字符以能够发布xml标签-上次我遇到了同样的问题)。另外,什么是“自定义配置对象”?我更喜欢零编码来实现这一点,因为在此阶段进行编码更改会使我们退缩很多。
DeeStackOverflow

自定义配置肯定涉及[简单]编码。但是恕我直言,它始终是您的最佳选择。我几乎从不使用appSettings,而是为每个项目创建一个自定义配置。
波特曼

3

通常,我最终会编写一个带有属性的静态类,以访问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

您可以app.config针对所描述的场景使用环境变量

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

然后,您可以轻松获得以下路径:

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

2

在里面<appSettings>您可以创建应用程序密钥,

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

稍后,您可以使用以下方法访问这些值:

ConfigurationManager.AppSettings["Keyname"]

要使用ConfigurationManager类,您需要添加对System.Configuration的引用并为System.Configuration(在VB中导入)添加using语句
cjk

2
该指示是正确的,但不是对所提问题的答案。
迈克尔卡彭铁尔

1

我建议你DslConfig。借助DslConfig,您可以使用全局配置中的分层配置文件,每个服务器主机的配置来配置每个服务器主机上的每个应用程序(请参阅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")

0

我认为您不能在配置文件中声明和使用变量来定义appSettings键。我一直在像您一样的代码中管理串联。


0

我在想些什么,但可以将替代文件添加到应用设置中,然后在每个环境中设置该替代文件。

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

0

对于推出需要配置大量具有相似值的项目的产品,我们使用小型控制台应用程序,这些应用程序读取XML并根据传入的参数进行更新。安装程序在询问用户输入的内容后会调用这些程序。要求(提供)的信息。


0

我建议遵循Matt Hamsmith的解决方案。如果实现时遇到问题,那么为什么不在AppSettings类的后台创建实现该扩展的扩展方法呢?

就像是:

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

    }

在该方法内部,您使用Linq搜索DictionaryInfoConfigSection,然后返回具有匹配键的值。不过,您需要将配置文件更新为以下内容:

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

0

我想出了以下解决方案:

  1. 在应用程序Settings.settings中,我定义了一个变量ConfigurationBase(类型为string Scope = Application)
  2. 我在Settings.settings的目标属性中引入了一个变量,所有这些属性都必须设置为Scope = User
  3. 在app.xaml.cs中,如果ConfigurationBase读取了值
  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。


0

三种可能的解决方案

我知道我来晚了,我一直在寻找是否有任何新的解决方案来解决可变配置设置问题。有一些答案可以触及我过去使用的解决方案,但大多数似乎有些令人费解。我以为我会看一下我的旧解决方案,并将实现放在一起,以便对陷入同一困境的人们有所帮助。

对于此示例,我在控制台应用程序中使用了以下应用程序设置:

<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

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

生成前事件:

项目设置->构建事件

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.