Article Source: http://geekswithblogs.net/michaelstephenson
Versioning is one of the more difficult aspects of a BizTalk project mainly because of the ability to deploy side by side versions of the components within a BizTalk application and the fact that often a BizTalk project would require long running processes making it more difficult to do deployments. There are a couple of useful resources available on this area:
In the MSDN documentation for BizTalk there is a page
which discusses versioning and the 2 main strategies for it. This is useful but from my experience I think it misses a couple of things and is wrong in relation to the BAM files
This web cast
includes a discussion around BizTalk versioning (mainly focusing on how to partition your BizTalk artefacts)
Nick Heppleson wrote an article
about how you can use assembly redirection with BizTalk
While all of these articles are great there is a gap in that nothing really talks about how to implement a versioning approach in your development process. In the rest of this article I will discuss some of the different considerations and how we implemented dynamic versioning for our BizTalk projects at my current project. I will also provide links to a sample which shows this.
Considerations for Versioning with BizTalk
There are a number of different things you should consider for your versioning strategy which are discussed below.
Type of Versioning
There are two main types of versioning which are discussed in the MSDN article above:
In static versioning you would normally keep the Assembly Version Number the same all of the time and only increment the Assembly File Version with each build. This is the most common type of versioning approach I have seen used.
In dynamic versioning you would increment both the Assembly Version and Assembly File Version with each build. The most common way I have seen this implemented is to manually change these version numbers (this subsequently requires a number of changes to files within the project)
The way you plan to deploy your application can have an affect on the versioning approach you might use.
- Replace application every time
Some BizTalk applications implement processes where there are clear windows where a deployment can be done. There are no significantly long running processes and it is easy to drain the system of in process messages. In this case when you deploy a new version of the application you would be likely to completely remove the existing BizTalk application and then add the new version.
This approach is well suited to either of the 2 types of versioning.
If you have a BizTalk project where you can not get a clear deployment window and you can not drain the system then your deployment approach needs to be able to support running multiple versions of processes at the same time. In this case you are essentially applying updates to your existing application and when the older instances have completed you may remove the old assemblies.
Latest Version for Development
One of the challenges is how within your code base you will implement these side by side versions and develop/test against them. When we deploy an official version we will take those assemblies and add them to an external libraries folder within our code base. When we build the code we will also deploy these older versions of the code and then run tests against this combined solution. One key thing we do is that we version the BizTalk project files in the code base to be version 999.999.999.999. When we do a local developer build we do not change the version numbers we only do this on our build server when the build is ran by Cruise Control. We need to ensure that the assemblies built from the code will always be the latest version when doing a developer build so we chose this approach.
What types of files do I need to care about for versioning?
There are a number of different file types you need to care about when applying versioning. In my opinion the above article on MSDN doesn't cover everything it needs to so here are my thoughts below:
We already use an approach of tagging the binding files to support changing the configuration for different environments based on stuff I have discussed before in other blog posts. In a binding file any references to assemblies will typically use the strong name for that assembly. When we apply dynamic versioning in the development process we will need to update parts of the binding file in each build to ensure the binding file continues to be valid.
If this is not done correctly the we could get problems importing a binding file.
Web Service Description Files
If you publish any web services from your solution then you may choose to save the web service description files and then regenerate the web services as part of your build. We save these files and have MsBuild tasks to support regenerating these web services with each build for WCF/WSE2 and standard SOAP web services. When we apply version updates we need to amend the WebServiceDescription.xml file that is published before we do the build.
BizTalk Map files may contain references to assemblies if you execute an external assembly using the scripting functoid. We need to ensure these maps are updated if the assembly version is changed. If we do not do this we may get errors while executing the map.
BizTalk Pipeline files may have references to external pipeline components or schemas or other assembly references in custom configuration. If we apply dynamic versioning we need to be aware of the impact on these files and make appropriate updates to ensure the pipeline still works when it is compiled.
If you use BAM on your project then your solution may contain Tracking Profiles or BAM Observation Models. The BAM Observation Model does not contain information relating to assemblies, but if you use any Tracking Profiles (.btt files) then they may contain references to assemblies which may need to change as you change the version number. In the MSDN documentation it indicates that .btt files are in binary format which Im not sure is right as the ones on our project are clearly XML files. Based on our experience you can just update these files to change the version numbers.
One side comment is that you can also use the Typed BAM API project on CodePlex which will mean you don't have to worry about Tracking Profiles.
If you manage your BRE policy as an XML file which you import and export then you may also need to update version numbers in it if you reference assemblies.
Some configuration files in your solution may have assembly references in them. You may need to update the version numbers here too.
Our Versioning MsBuild Tasks
As you have read so far there are a number of different tasks which need to be done to implement versioning. We have developed the following list of MsBuild tasks which help us to do this in our MsBuild process. Note the code for these tasks is available in the accompanying sample.
This task will look for any .btproj files within your solution directory (including sub directories) and then update the version attributes of the project file to take the value from Cruise Control
This task will create a file called VersionNumber.cs which contains the C# attributes for versioning an assembly. All of the C# projects within our solution reference this file and pick up its version number when they are built.
This task is given a list of files which need to be inspected for versions to be updated. The task will use the assembly name regular expression, assembly public key token, assembly culture and assembly version regular expression to identify strong names within the file that need to be updated. Once a strong name is found the version number part of it is updated to the version passed into the task by Cruise Control.
Note that this task is also used to update any BRE policies which are stored as XML files in the solution.
This task does the same as the apply version to adhoc files task however this task needs to force the file to be rewritten in a the right encoding for the web service publishing wizard to use.
This task is given a list of paths to binding files which it needs to update. In the binding files it will look for strong names in the same way as the adhoc files task and update them. In binding files there are also some other formats in which assembly version numbers are stored so this task will also handle these to ensure that the binding file is correctly updated.
This task will start at the root directory of the solution and look for all BizTalk artefacts which may require updating (Maps, Pipelines, Tracking Profiles). For each of these file types it will look for assembly references based on the strong name patterns provided and apply the updates to the version numbers which come from Cruise Control.
Setting up a new solution to use dynamic versioning
When we are starting with a new solution and we want to be able to implement the dynamic versioning straightaway there are a couple of standards we use.
C# Project Files
In our solution it is common to have C# projects to compliment our BizTalk projects. We take the approach of versioning these assemblies by adding an existing file to the project which includes the below code snippet (we usually call this file VersionNumber.cs and it is located in the root folder of the solution). This means that the assemblies are all versioned to the standard 999.999.999.999 during development
When our MsBuild process executes it will overwrite this AssemblyVersion.cs file and replace the version numbers in it to the version label taken from cruise control. We use our AssemblyVersion custom MsBuild task. There are a number of different tasks in the community and Microsoft.Sdc tasks which can do versioning of C# projects and using any of these should be sufficient.
BizTalk project version numbers
On all of the BizTalk projects within the solution we will amend the project properties (see pic below) to set the version attributes to the fixed 999.999.999.999. This will mean during a local developer machine build all of the BizTalk assemblies will be versioned as 999.999.999.999. When Cruise Control runs a build the extra build tasks will run and execute our BizTalkProjectAssemblyInfo custom MsBuild task. This will update the version numbers of all of the BizTalk project files within our solution to apply the version number from Cruise Control.
As we will have applied the 999.999.999.999 version number to our projects before we start adding artefacts to the projects then any files we add will correctly pick up these versions and we will not manually need to update them.
The Cruise Control Integration Bit
In the below picture you can see the Cruise Control configuration used for the Continuous Integration of this solution. In the tasks bit you can see we basically call 3 MsBuild scripts as follows:
- Apply versioning to the files in the solution
- Perform a debug/development build of the solution (including executing tests)
Perform a release/deployment build of the solution (including executing tests)
The bit we have added is the first step where we will call ccnet.targets MsBuild script. This file is in the solution and is where we will call the tasks to apply versioning.
Setting up the CCNet.targets File
The below picture shows the contents of the ccnet.targets file. This file will basically call the list of MsBuild tasks in the ApplyVersion target which will apply versioning to all of the appropriate files. Each of these tasks was discussed in detail earlier in this article.
In the property group at the top of this file you can see that we have defined some common attributes which each of the tasks uses to do its job. These properties are used as follows:
This is a pattern used to identify the name of assemblies. In our case the assemblies will usually be called something like Acme.Something.BizTalk….
We use the regular expression Acme.Something.BizTalk.?\w* which will find assemblies with the right names for us for example:
All of our assemblies have the culture neutral so we use this as a static value in the script
All of our assemblies have the same strong name applied usually so we can just keep this as a static value of the public key
This property is a regular expression which you will use to identify version numbers that need to be changed. In our case because we use the fixed version 999.999.999.999 to indicate it needs to be dynamically changed we just use this value. Having this as a regular expression however allows some flexibility on how you might use this
As you can see from the order of calls to our tasks we version the files in the following order:
- BizTalk project file
- C# project file
- Adhoc Files
- Web Service Description Files
- Binding Files
- BizTalk Artefacts
The order here isn't really that important as long as all of these activities are done before compiling the solution.
Converting an existing solution to use dynamic versioning
This walk through will explain how to configure an existing BizTalk solution to use dynamic versioning rather than static version approaches described above. One key point to reiterate here is that on a developers machine we always do builds as our fixed 999.999.999.999 version number and it is only on the continuous integration build server that we run the additional tasks to do full versioning as described below.
Reconfiguring parts of the solution
C# & BizTalk Project Files
We will need to update the BizTalk and C# projects to reference the 999.999.999.999 version number. We can do this the same as how is described in the section about setting up a new solution for dynamic versioning.
Updating Map Files
Maps are slightly strange. In the map if you reference an external assembly and execute it via the scripting functoid then you need to be aware that the strong name for executing assembly may need to change. In the MSDN documentation explaining this it indicates you need to change maps, but if you disassemble an assembly containing maps and the C# project was referenced as a project assembly then the compiler seems to change the xslt within the map for you. However as this is a little unclear we decided to change the maps anyway.
To do this we needed to open the map using the XML Editor in Visual Studio. We then would change the version numbers highlighted below as 184.108.40.206 (in the pic below) to 999.999.999.999 for all of the assemblies we know we are going to dynamically version.
We would do this for every map in the solution. When Cruise Control runs the build it will modify and strong names in .btm files which need to be versioned.
Pipelines are similar to maps in that under the .btp file is XML which may contain assembly strong names (see picture). Again we would open the file using the Visual Studio XML Editor and change the version numbers from 220.127.116.11 to 999.999.999.999 for any references to assemblies we are going to dynamically version.
When the build is ran by Cruise Control our additional tasks will find all of the details we need to change and modify the .btp file before it is compiled.
Binding file template
In the solution we have a template binding file which contains tags which we use to configure the binding file for different environments. In a binding file there are lots of references to assemblies by their strong name. If we have any assemblies which we know are going to be dynamically configured then we will replace their version with the fixed 999.999.999.999. In the below picture you can see an example binding file template which shows the version numbers before they have been amended.
When Cruise Control runs our build then an additional step is ran which will execute our ApplyVersioningToBindingFiles task. This will modify the binding file correctly to replace the version numbers with the appropriate label from Cruise Control.
In some of our solutions we include configuration files which may have assembly version numbers in which need to be dynamically versioned. We follow the same approach to make the version number 999.999.999.999 if it needs to be dynamically configured.
In the Cruise Control build a task called ApplyVersionToAdhocFiles is called passing in a list of these adhoc files.
Web service description Files
In some of our solutions where we publish web services from BizTalk we use a couple of MsBuild tasks in our build process which will support regenerating these web services each time the build is ran by using the WebServiceDescription.xml which is produced by the Web Service Generator Wizards. We have MsBuild tasks which support WSE2, SOAP and WCF.
When we use this technique we also need to apply updates to any version numbers which may need to change in the WebServiceDescription .xml. To do this we use the same approach of replacing the versions with 999.999.999.999 for the developer build and then Cruise Control will run the ApplyVersionToWebServiceDescription task to do the dynamic updates.
BAM Tracking Profiles
The BAM tracking profile is an XML file under the hood and we again replace the version number of any of our assembly strong names with 999.999.999.999.
When the Cruise Control build runs it will execute a task which will apply the Cruise Control version label in place of our version number and then when the build deploys BAM artefacts they will be already versioned correctly.
(For details of how we integrate BAM into our MsBuild process please refer to: http://geekswithblogs.net/michaelstephenson/archive/2008/06/15/122870.aspx)
BRE Policy Files
When we use BRE we usually take the approach of managing the policy as an artifact in the solution. We use custom MsBuild tasks to import and export the policy from BRE and store it in the solution as an XML file. If we reference any assemblies in the policy that need to be versioned then we will amend the xml that is exported from BRE and make the version numbers the usual 999.999.999.999. In terms of Cruise Control we treat the BRE exported XML file the same as an adhoc file which requires version updates. We then use the ApplyVersionToAdhocFile task to update this
If you would like to know more about how we implement the BRE features of our build process please refer to the following article: ???
!!!!!! vWhere is BRE post !!!!!
Check local build
Finally when we have done all of the above steps we will run a local developer build to see that the solution is fully versioned, compiles correctly and deploys. We also ensure that the build has ran our BizUnit tests and they are all successful.
The next stage is to get Cruise Control to so some extra stuff.
The Cruise Control Integration Bit
When modifying an existing solution to use dynamic versioning, the requirements for the ccnet.targets file and Cruise Control to implement the version updates is exactly the same as when you setup a brand new solution for dynamic versioning. For details please refer back to that section.
At this point you can see it is a fair about of work to modify an existing solution to use this versioning technique. I think the earlier you do it in your project life cycle the better. You can use things like Replace All to modify some of the version numbers manually when doing the above tasks but be careful when doing that as you may not want to change all version numbers.
Frequently Asked Questions
In relation to this topic the following questions have occasionally came up.
How do I do side by side versioning in development for a new major release?
The approach described in this article is entirely intended to support development of side by side versions of the same solution. Imagine you have version 18.104.22.168 of your application deployed and we know you want to now work on version 2.0.n.n. You know from your understanding of this topic that you will employ a deployment model which will mean you will have multiple versions of some of your assemblies deployed.
The way you could implement this is to add external Library folder within your solution store the version 22.214.171.124 versions of all of the deployed assemblies. You could also store the appropriate development binding files and any other artefacts to support this update. In your build script you might setup and deploy the existing application (v126.96.36.199) and then modify your build script to apply updates to the application by deploying some or all of your newly compiled code.
In development the newly compiled assemblies always have a very high version number they will always be the latest version and the versioning rules will apply correctly. You will probably also do things like modify binding files to be able to work with two versions of the assemblies. In the binding file remember that the way we do this only our assemblies which are versioned 999.999.999.999 are dynamically changed so if you add details of an older version of the assembly to the binding file we will not touch that instance of a string name as the version number within the string name will not be 999.999.999.999.
When your code is checked in and build on your build server Cruise Control would apply the correct 2.0.n.n (provided you have updated the major number in its config) version number and your build will allow you to have a correctly configured and working side by side versions of the application.
What's the 999.999.999.999 thing all about?
In applying dynamic versioning to the solution we need to be able to ensure that in our development environment a developer can work on a solution which may have side by side versions. We have chosen to use 999.999.999.999 to indicate this is a developer machine only version of the assembly and it is given a high version number to ensure that when it is build it will always be the latest. Although the build tasks accept a regular expression for the version number which needs to be replaced we find it keeps things simpler by always using this fixed number.
Because we use source control we can not apply dynamic versions on a developers machine local build because the files we need to modify will be read only. A developer will always build version 999.999.999.999 of the solution. When the developer checks code in Cruise Control will replace all of these developer 999.999.999.999 versions with the build label from Cruise Control.
BizTalk 2009 Update
Following the release of BizTalk 2009 CTP I have had a brief look at how the new version would affect this versioning approach. In my opinion the approach stays very much the same with the exception that now BizTalk project files are MsBuild based and you can use the AssemblyInfo file to version the assembly rather than the old BizTalk project file. Based on this the change to our implementation would be to not use the old VersionBizTalkProjectFile task and just use the C# one for BizTalk projects as well.
As you can see from this article this isn't a trivial undertaking. If you do it right from the start of the project then hopefully you will find things a lot easier.
Hopefully this article will plug the gap I identified at the start and there is now a detailed walk through of applying effective dynamic versioning to BizTalk projects which use continuous integration. If you would like to look at the code for the MsBuild tasks we used to help us implement this approach then please refer to the following location:
(Note some companies block access to box.net so if you are unable to get the sample please email me via the blog)