When you are building a .sln file or a .csproj/.vbproj/etc you need to be careful how you set the Configuration property. Once this property is set you do not want to change the value of it. Because of this it is best to specify this as a global property. To do that you can pass it in on the command line. If you are using the MSBuild task then you can pass it in via Properties or AdditionalProperties. What you do not want to do is to set this value inside your .csproj/.vbproj or any imported file. The only time when this is OK if there is a condition which will not set the property if it’s already been set. This is exactly how the default .csproj/.vbproj files are authored:
Debug
If you do set this property w/o the conditional not to overwrite an existing value you may experience really strange behavior during your builds. And it may be difficult to diagnose the issue as well.
Now let me explain why you cannot do this. When you build a .csproj/.vbproj MSBuild will start creating an in-memory representation of the entire project. It will start with the .csproj/.vbproj file itself. It will read the file from top to bottom. When a property is encountered it is evaluated. If a property is encountered that relies on another one, for example
$(BaseIntermediateOutputPath)$(Configuration)\
The properties inside the expression will be evaluated on whatever values exist for the properties at the time. In this case ItermediateOutputPath will be the value of BaseIntermediateOutputPath and Configuration.
If a property is encountered which specifies a value for a property which has been previously declared, the previous value will be discarded.
The implications of this are subtle but very simple; once a property has been set which has dependent properties you must not overwrite that property. This is because when a dependent property is encountered it is evaluated immediately. You cannot re-evaluate that property. So if you set a property during your build, some existing dependent properties which were evaluated before the value change will continue to use the old value. There is no way to re-evaluate those properties.
Now lets see how this relates to the Configuration property specifically.
The contents of the .csproj/.vbproj are properties/items along with an import to Microsoft.csharp.targets (Microsoft.VisualBasic.targets for .vbproj) which then imports Microsoft.Common.targets. If you look in Microsoft.common.targets you will see many different properties which are declared using $(Configuration). So this means that you must treat the Configuration property with care and abide by the rule that I have outlined above.
FYI If you want more details on this I have explained this entire process in great detail in my book Inside MSBuild and Team Build.
Configuration for web publishing
If you have used the new web publish experience in Visual Studio 2012 (also available for VS2010 from the Azure SDK) you may have noticed that the web publish profiles are MSBuild files. They are stored under Properties\PublishProfiles (My Project\PublishProfiles for VB) and have extensions of .pubxml. In that file (or in a .pubxml.user file associated with it) you will find a property defined as
Release
This value corresponds to the value for the Configuration drop down in the VS web publish dialog. When you kick off a publish in VS we use this value and kick off a build and specify Configuration as a global property which is passed in. The reason why we did not name this property Configuration is because the web publish profile is imported into the web project itself during the publish process. By the file being imported you can natively access all the properties/items of the .csproj/.vbproj and also easily extend the build process. Since that is the case we cannot set the Configuration property because we know it’s value has already been set. Due to this when publishing from the command line you must specify the Configuration property.
Sayed Ibrahim Hashimi | @SayedIHashimi
Comments are closed.