Microsoft puts it best in their documentation:
When you deploy a Web site, you often want some settings in the deployed application’s Web.config file to be different from the development Web.config file.
For example, you might want to disable debug options and change connection strings so that they point to different databases.^1
The project I currently work on has nine environment configurations with a tenth one potentially in the works.
Dev, Test, and Load have two environments each to support two releases.
Initially, we did only have a single instance for each environment, but development teams started halting when those environments were going through the deployment process.
While one is being finalized (bug-fixes found in a higher environment, stage-gate-reviews, security scanning, etc.) development on the next release can continue without impeding other teams.
User Acceptance Testing (UAT), Train, and Prod only have a single environment because they are focusing on accepting a single release at a time.
As far as I know Demo is no longer operational and should probably be removed.
Although, a new environment called Diag has servers set up but none of the configuration information has been communicated to the development team - yet.
log4net is a logging framework for .NET.
log4net webpage describes it as:
The Apache log4net library is a tool to help the programmer output log statements to a variety of output targets.
log4net is a port of the excellent Apache log4j™ framework to the Microsoft® .NET runtime.
We have kept the framework similar in spirit to the original log4j while taking advantage of new features in the .NET runtime.
For more information on log4net see the features document.
log4net is not my preferred logging library; (mostly) due to performance concerns.
Although, the article’s publish date is January 12, 2016 - which is a lifetime for a software application - meaning it is possible these concerns have been addressed and resolved.
log4net‘s NuGet Page reveals that only three versions have been released since the article was published.
This does not invoke confidence that the performance concerns have been addressed and resolved.
Unfortunately, that does not help,
log4net v1.2.10 (release January 7th, 2011) is the version required by the dependency assemblies embedded as part of the applications.
There is no choice but to accept
log4net as a dependency in this project - for the time being.
These dependency assemblies must have
log4net.config files - for each environment configuration.
When we took over the project, all of the
log4net.config files were bundled as part of the release and the environment’s
web.config file had an
appSetting that was used to select the proper
log4net.config file for that environment.
The purpose in describing this is to illustrate why I set out to make the
log4net.config files in my project behave like
To start, I created a base file called
log4net.Template.config (more on ‘why’ later).
This file will hold the initial configuration information that can be transformed for each environment.
It is set up something like this:
Then a separate
log4net.config file is created for each environment (such as
log4net.Debug.config) and nested under the base configuration.
These configurations can remove pieces of the base template when transformed like so:
Or, the configuration can change specific settings - like the
appender‘s type or connection string:
Finally, an empty
log4net.config file is created in the project.
The file is included as part of the project so that it can have a
Build Action associated to it, be ‘built’, and be included as part of any artifacts generated from the process.
The contents of this file will be overwritten with the environment configuration selected, which is why a
log4net.Template.config file is used as the base instead of
This will prevent the base from being lost after the first transform is applied.
It is best to leave the contents blank and exclude any additional changes from source control to preserve a clean source control history.
The end result looks something like this:
The next step is to get Visual Studio and/or the build server to apply the transforms that were set up.
Visual Studio does not apply transformations for any configuration file in the project/solution - except the
web.config file (and even then that is only when special circumstances have been met that will be mentioned in the next section).
To get Visual Studio to transform the
log4net.config file, a build step must be configured for the project.
There are two ways this can be done.
- Project Build Events
- Project Build Targets
Use build events to specify commands that run before the build starts or after the build finishes.
Build events are executed only if the build successfully reaches those points in the build process.^2
Project build events are configured by right clicking on the
StartUp project in the
Solution Explorer and selecting properties (
Alt+Enter when project is highlighted).
In the window that appears, navigate to the
Build Events tab.
This method has the advantage of only performing the
Post-Build Event when a selected criteria is met.
The other method is to create
MSBuild includes several .targets files that contain items, properties, targets, and tasks for common scenarios.
These files are automatically imported into most Visual Studio project files to simplify maintenance and readability.^3
To do this, the
StartUp project in the
Solution Explorer must be
Unloaded (some versions of Visual Studio may allow the project to be edited directly):
This allows the project to be
Edited in Visual Studio (with the benefit of syntax highlighting):
When all changes have been made, the project can be
Alternatively, it can be opened in an external text editor (may have limited syntax highlighting):
The project will re-load every time Visual Studio becomes the active window and detects that changes were made to the project.
Each method has pros and cons - my project opted for the
Project Build Targets method which will be outlined here.
Regardless of the chosen method, the same tasks need to be run:
The first one is obvious, and may seem like it should be the only one that needs to be done.
Regardless of the method chosen, the same steps need to be applied.
My project opted to use the
Project Build Targets method.