views:

298

answers:

6

.NET allows you to use .settings files to manage application settings. I would like to store Production, Development and Test settings separately in a way that I can do something like this:

EnvironmentSettings environmentSettings;

// get the current environment (Production, Development or Test)
ApplicationEnvironment Environment = (ApplicationEnvironment)
    Enum.Parse(typeof(ApplicationEnvironment), Settings.Default.ApplicationEnvironment);

switch (Environment)
{
    case ApplicationEnvironment.Production:
        environmentSettings = Settings.Production;
        break;
    ...
}

string reportOutputLocation = environmentSettings.ReportOutputLocation;

Basically, I want two separate Settings classes: the general Settings class that stores the selected environment and non-environment specific properties, and 3 static instances of a second class called EnvironmentSettings. The instance used should depend on the environment specified in the general Settings class.

Is there any way to do this short of manually setting the values for all these settings in a static constructor or something? If I have to do that, I'd rather just have one big Settings class with properties like "DevOutputLocation", "LiveOutputLocation", etc.

I can have multiple .settings files in my project but that just creates separate classes that don't derive from each other. So I could make DevelopmentSettings.settings, ProductionSettings.settings and TestSettings.settings files and give them the same properties, but then I would need a bunch of switch statements everywhere to determine which class to use because they don't derive from a common class.

A: 

Just an idea but it may work...

  • You'll need N+2 settings files (N different builds; 2 masters) with containing the same keys.

  • Clear out the "Custom Tool" property for all of them but one of the masters (so only one the master generates).

  • Modify the pre-build script for each release to copy the appropriate settings file contents into the build-master file.

  • Modify the post-build script to copy the secondary master file contents back in to the original master file.

Note: If you can work with your source control provider in the pre- and post-build scripts, you don't need a secondary master -- you can just check out in the pre-build and undo check out in the post-build. However, this may cause issues in a continuous integration environment since a locked file would require the build to fail.

I've also never done this; though there are times I wished there was a more up-front way of doing something like this in VS.

Austin Salonen
A: 

One thought is that switching between a series of static values sounds like a rather fraught way of doing things. I would suggest looking up the Singleton pattern. This pattern gives you a single class instance that is shared between all references to the class, but when it's first loaded you can do your normal initialisation bits to check your environment and set the values accordingly.

Equally, rather than using switches to act on different classes, wouldn't you be looking at designing one Interface, and having each class implement that interface?

David Burton
+1  A: 

I am using this approach for .config files, I am sure that it will help you too. Just look on Scott Hanselman's blog post and this question. Ideology is simple like hell, but works pretty good. All you will need is:

  1. create several files for different configurations
  2. name them by convention, e.g. my.dev.settings, my.live.settings
  3. create post build event (see links)
  4. enjoy =)

Instantiation code for you class with settings will always look in default settings (which will be replaced after each build with the needed one), so this approach require minimal effort.

Restuta
Is this really the only way? I suppose so if it's endorsed by Scott H. It just seems like a really messy hack. You would think you could specify what .settings or .config file to use for each build configuration.
Carl
A: 

Just some extra info on .NET environment based config files without using your above implementation specifically:

The Enterprise Library has this feature since V3.0: Summary

Visual Studio 2010 will have this feature also. Its called Config Transformation

Ben Dempsey
A: 

There is a bit of overhead involved in making a check to determine what environment you are running in. If you are talking a web environment then this could mean a significant performance hit. I would recommend creating three separate config files and setting up a continuous integration and deployment system that handles the naming and roll out of the proper settings file based on environment. In your case you would have three files, Production.config, Development.config, and Test.config. The integration server would then create a copy of this file for web.config or app.config based on the environment.

As far as any additional maintenance involved with maintaining three separate files whenever a configuration change is made, we keep the files auto-formatted and use something like WinMerge to easily see differences and keep them in proper sync. These type of files typically do not require many changes and when they do they are usually minor additions.

pdavis
A: 

I currently do something similar to the solution mentioned by pdavis. But to simplifying multiple config files I use a T4 templates to create the environment specific config files. That way there is one web.tt file that handles the generation of the default web.config file. Each environment has its own template file (qa.tt, production.tt, etc) that inherits from web.tt and contains any environment specific overrides. Any changes to web config - new app settings, configuration settings, etc. are automatically propagated to all region specific config files by regenerating the templates, and you don't have to worry about keeping files in sync using a diff tool.

Matt Otto