views:

7283

answers:

10

I was wondering if it is possible to do something like this in the app.config or web.config:

<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 app 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).

Would anybody know?

+3  A: 

Inside <appSettings> Tou can create application Keys

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

Later on you can access these values using:

ConfigurationManager.AppSettings["Keyname"]
Sergio
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)
ck
The indication is correct but isn't an answer to the asked question.
Tyalis
A: 

I don't think you can declare and use variables to define appSettings keys within a configuration file. I've always managed concatenations in code like you.

Tyalis
A: 

I'm struggling a bit with what you want, but you can add an override file to the app settings then have that override file set on a per environment basis.

<appSettings file="..\OverrideSettings.config">
Andrew Barrett
+2  A: 

You have a couple of options. You could do this with a build / deploy step which would process your configuration file replacing your variables with the correct value.

Another option would be to define your own Configuration section which supported this. For example imagine this xml:

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

Now you would implement this using custom configuration objects which would handle replacing the variables for you at runtime.

JoshBerke
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.
DeeStackOverflow
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.
Portman
+1  A: 

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

Scott Weinstein
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.
DeeStackOverflow
A: 

For rolling out products where we need to configure a lot of items with similar values, we use small console apps that read the XML and update based on the parameters passed in. These are then called by the installer after it has asked the user for the required information.

ck
+1  A: 

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 MS is creating a mechanism in VS2010 for deploying different config 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 whats at work there...

Heres 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>
Arjan Einbu
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
The DataDirectory value is actually a data element in the AppDomain. You could override the value by using AppDomain.CurrentDomain.SetData("DataDirectory", dataPath);I haven't tested if you can define other variables like this and get them "autoexpanded" though...
Peter Lillevold
+4  A: 

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["DirectoryInfo"];
            }
    }

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

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.Dir1Resolved;  // This value will equal "C:\MyBase\Dir1"
Matt Hamsmith
Thanks but I am trying to do this without modifying any code as it is a pain at this stage.
DeeStackOverflow
+1  A: 

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.

Martin
A: 

I would recommend following Matt Hamsmith's solution. If it's an issue to implement, then why not create an extension method that implements this in the background on the AppSettings class?

Something like:

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

    }

Inside the method you search through the DictionaryInfoConfigSection using Linq and return the value with the matching key. You'll need to update the config file though, to something along these lines:

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