During development, testing and support stages of the project, there is usually a need to test or debug code against multiple environments: Local with and without Azure emulation, Dev environment, QA environment, UAT environment, perhaps even Prod environment, etc. Configuration changes can get very complicated when servers, URL’s, connection strings, etc. need to switch in unison when switching between different environments. In general, handling more than one environment from Visual Studio can be very laborious when the overall project structure is complex. Throwing Windows Azure in the mix only adds to debugging and deployment vows.
This article will describe techniques that we use to manage configuration changes among various projects in a large distributed Azure-based solution called AzureWatch and keep settings in sync as various environments are targeted during development, testing, and debugging sessions. AzureWatch is an auto-scaling and monitoring system for Windows Azure applications. By its nature it utilizes multiple WCF services, a few Windows-based clients and services, a number of web-based projects. As readers can imagine, keeping all configuration settings in sync and "shifting" them together on demand without making a mistake can be challenging.
Visual Studio technologies utilized
Approach at a high level
For every debugging environment, create Visual Studio Configuration. Break out sections from every .Config file that vary by environment and include them back via ConfigSource settings. Include these sections as unique files into a separate Config project that has folders for every Configuration. Also, copy *.csdef and *.csccfg files from Azure-related projects into these folders as well. In each folder, customize the broken off partial configuration files (that are included via ConfigSource) and azure configuration files. Create Post or Pre-Build event of the Config project to xcopy the files from a folder that matches current Configuration environment to root folder of Config project. Include files from root folder of Config project into other projects as needed via “Add as Link” command.
Utilize Config transformations to instrument Production (and other environments if needed) specific configuration changes that deal with security, debugging, tracing, etc.
Now, let's look at these steps in detail:
Create as many Visual Studio Configurations as necessary to support number of different environments that developers must be able to debug from Visual Studio
Create a separate empty project that is a part of the overall solution called Config. Include into the project folders, one per matching Visual Studio Configuration environment that were created in Step 1
Break-off Connection strings, end-point configuration, and other environment-specific sections from existing .config files into separate “include-only” config sections.
Source example web.config:
Broken off example connectionStrings.config:
<add connectionString="..." name="db_connection"></add>
May want to make sure that web-projects have "bin" folder as a part of the relative path: "\bin\config\partialConfigFileName.config"
Include separate customized partial .config files and Azure-specific .cscfg files under every sub-folder within Config project
Customize Pre-Build event for Config project to copy config files for current configuration to root folder:
xcopy /Y /R "$(ProjectDir)$(ConfigurationName)\*.config" "$(ProjectDir)"
xcopy /Y /R "$(ProjectDir)$(ConfigurationName)\*.cscfg" "$(ProjectDir)"
Add-as-Link partial .config files into main projects from the ROOT of the Config project. To keep things organized, feel free to include partial .config files under Config sub-folders. Do the same with Azure-specific .cscfg files
Files added as links have a shortcut icon in Solution Explorer
Manually add project dependencies to Config project from the other projects in the solution, that need partial config files to function. This will ensure that Config project is built before other projects. Project Dependencies can be found inside Solution Properties window, under "Project Dependencies" tab.
Do not forget to specify that partial config files set "Copy to Output Directory" as "Copy if Newer"
You can still use Config Transformations to strip out debug information from Release configuration setting that will be ultimately used for publishing.
Now, every time you debug and run, the pre-compile event from Config project will copy all the files from its particular environment folder into its root folder. And all other projects that link to this root folder for their partial .config files will automatically get updated .configs switched to proper environment in unison.
This blog was revised on 06/10/2012 to include the extra XCOPY step that keeps Azure cscfg/csdef files in sync with the Config project