Variables within app.config/web.config

154,463

Solution 1

Good question.

I don't think there is. I believe it would have been quite well known if there was an easy way, and I see that Microsoft is creating a mechanism in Visual Studio 2010 for deploying different configuration files for deployment and test.

With that said, however; I have found that you in the ConnectionStrings section have a kind of placeholder called "|DataDirectory|". Maybe you could have a look at what's at work there...

Here's a piece from machine.config showing it:

 <connectionStrings>
    <add
        name="LocalSqlServer"
        connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
        providerName="System.Data.SqlClient"
    />
 </connectionStrings>

Solution 2

A slightly more complicated, but far more flexible, alternative is to create a class that represents a configuration section. In your app.config / web.config file, you can have this:

<?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>

Then, in your .NET code (I'll use C# in my example), you can create two classes like this:

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

Finally, in your program code, you can access your app.config variables, using your new classes, in this manner:

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

Solution 3

You can accomplish using my library Expansive. Also available on nuget here.

It was designed with this as a primary use-case.

Moderate Example (using AppSettings as default source for token expansion)

In 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>

Use the .Expand() extension method on the string to be expanded:

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

or

Use the Dynamic ConfigurationManager wrapper "Config" as follows (Explicit call to Expand() not necessary):

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

Advanced Example 1 (using AppSettings as default source for token expansion)

In 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>

Use the .Expand() extension method on the string to be expanded:

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

Solution 4

I thought I just saw this question.

In short, no, there's no variable interpolation within an application configuration.

You have two options

  1. You could roll your own to substitute variables at runtime
  2. At build time, massage the application configuration to the particular specifics of the target deployment environment. Some details on this at dealing with the configuration-nightmare

Solution 5

Usally, I end up writing a static class with properties to access each of the settings of my 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();
    }

}

Usually, I also do type conversions when required in this class. It allows to have a typed access to your config, and if settings change, you can edit them in only one place.

Usually, replacing settings with this class is relatively easy and provides a much greater maintainability.

Share:
154,463
DeeStackOverflow
Author by

DeeStackOverflow

Updated on September 28, 2020

Comments

  • DeeStackOverflow
    DeeStackOverflow over 3 years

    Is it is possible to do something like the following in the app.config or web.config files?

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

    I then want to access Dir2 in my code by simply saying:

     ConfigurationManager.AppSettings["Dir2"]
    

    This will help me when I install my application in different servers and locations wherein I will only have to change ONE entry in my entire app.config. (I know I can manage all the concatenation in code, but I prefer it this way).

  • cjk
    cjk about 15 years
    To use the ConfigurationManager class you need to add a reference to System.Configuration and add a using statement for System.Configuration (imports in VB)
  • DeeStackOverflow
    DeeStackOverflow about 15 years
    I don't see your xml in the post (indent your line 5 characters to be able to post xml tags - i had the same problem last time). Also, what are 'custom configuration objects' ? I prefer zero coding to achieve this as coding changes at this stage would set us back a lot.
  • Portman
    Portman about 15 years
    Custom configuration definitely involves [simple] coding. But IMHO it is always your best option. I almost never use appSettings, preferring instead to create a custom config for every project.
  • DeeStackOverflow
    DeeStackOverflow about 15 years
    That is interesting information. Maybe variables are accessed using the pipe symbol ("|")? Hmm.. I wonder if this will work: <add key="Dir2" value="|MyBaseDir|\Dir2"/>
  • DeeStackOverflow
    DeeStackOverflow about 15 years
    This is the correct post. My previous post (same question) did not show the app.config xml entry example. I checked your link - it is too much work and prefer not to spend time there.We have separate app.configs for different boxes and i want to get away from that.
  • Michaël Carpentier
    Michaël Carpentier about 15 years
    The indication is correct but isn't an answer to the asked question.
  • Ahmad
    Ahmad about 11 years
    I think this answer is very under rated!!
  • anderly
    anderly about 11 years
    Thanks Ahmad! Let me know how you like Expansive.
  • Ahmad
    Ahmad about 11 years
    Although this is runtime 'resolution' of app settings, it solves my issues of having repetitive key value pairs. We have significantly reduce our config maintenance using this. The absolute utopia here would be to have this being a build time plugin to work in conjunction with SlowCheetah. I would +1 again if I could. Great stuff anderly.
  • TheWho
    TheWho over 8 years
    There's a small error in the last line of code (not counting braces): "return System.IO.Path.Combine(MyBaseDir, Dir1);" should instead be "return System.IO.Path.Combine(BaseDirectory , Dir1);", or otherwise the method should be renamed from 'Base Directory' to 'MyBaseDir'
  • Ryan Gates
    Ryan Gates almost 8 years
    Can you please provide a brief example of how your library could be used to accomplish this?
  • cowsay
    cowsay almost 7 years
    For anyone else just now stumbling across this, the project has been dead for 6 years now, since 2011 :(
  • anderly
    anderly almost 7 years
    @user1003916 The project is not dead. It just hasn't been updated since then since it's fairly stable library. Additionally, with true string interpolation now in C#, there are other options if you don't need the Expansive library features.