Versioning Strategy for BizTalk Assemblies

I spent a bit of time today reviewing some best practices for assembly version in BizTalk applications, and wanted to also elicit community feedback.

One of the first things that a new BizTalk developer is told when building up a BizTalk solution is to not cram all the various artifacts into a single .NET project. Often that developer will be told to put schemas in one project, maps in another, pipelines in another, and finally orchestrations in an isolated project. I've become less of a fan of this rigid structure. But first, let's see how I'd do an upgrade of a solution configured this way.

I'm starting with a simple project, containing a single schema file. The message looks like this:

I built and deployed this project and constructed a simple "receive location" and "send port" where the send port had a subscription/filter on BTS.MessageType. I tested it, and everything travels through just fine.

Then I built a simple orchestration that makes a decision and writes to the event log. It looks like this:

I referenced the schema project, built, deployed and tested the orchestration successfully. The next step was to create a new version of the schema. So, I added a "Status" node, and then changed the .NET Assembly Version.

I then rebuilt and deployed the schema project. Now given that you've constantly been told that namespace#root has to be unique, the screenshot below may worry you.

If you want to read more about how pipelines resolve schemas, read here. So you may expect that I would get a "ambiguous reference" sort of error when I try and submit the inbound message now. However, when I drop the file, the orchestration still picks it up, processes it and continues on its merry way. But, what happens if I "stop" the orchestration so that I can see the message in flight, and investigate the SchemaStrongName property assigned by the pipeline? What you'd see is this:

Surprise. The schema resolved to the most recent version, and THIS is the one yanked in by the orchestration. This surprised me a bit. I would have expected the send port containing the BTS.MessageType filter to yank the most recent version of the schema since it only cared about "type", but I had thought the orchestration would only grab the version it explicitly referenced. Now if I try and remove the "1.0" schema assembly via the Admin Console, I get an error stating that the orchestration is referencing it.

So to get rid of the "1.0" schema project, I'd have to reversion the Orchestrations project with an updated build. Then after gracefully transitioning to the new "1.1" orchestration, I could safely remove legacy assemblies.

Now, if I used a custom receive pipeline, THEN it seems I can dictate the schema version the orchestration consumes (old schema or new schema). I tested this by putting a receive pipeline (with XML Disassembler and Validator components) in the project with the schema. I deployed that (version 1.0 again). Then, I upped the version to "1.1" and built and deployed. So, now I have schema/pipeline projects for "1.0" and "1.1" and an orchestration project still built with "1.0".

By switching the pipeline, the orchestration would grab specific versions of the schema. For instance, if I dropped a "1.0" message (no "Status" field) when the "1.0" pipeline was selected, everything ran fine. If I dropped a "1.1" message with the "1.0" pipeline still in place, I got a suspended message. Same situation when I flipped to the "1.1" pipeline. The orchestration consumed either the "1.0" OR "1.1" message.

So, any conclusions here? Changing .NET Assembly Version has broad impact, regardless of how you've factored your projects. One recommendation I've seen is to only change the Assembly File Version so that you still have an incremented build number, but the core .NET version stays the same (allowing for lower impact changes). However, that could get dicey if you are truly introducing breaking changes. You'll also see recommendations to version schemas by changing the namespace#root combination (e.g. changing the namespace to https://Microsoft.Project.BizTalkStuff.v1). Of course then you HAVE to change all the dependent artifacts (maps, pipelines, orchestrations) because you've made a core modification.

This leads me to a solution structure that is less segmented by artifact type, but more by artifact relevance. That is, group related artifacts in the same project. You still may have a "base schemas" project, but it's also ok to have a subsequent project that contains a few schemas, maps and orchestrations. Try and group the items that will change and version together. Now if I have to version the schema, I can fairly naturally version the sibling artifacts and deploy fewer assemblies.

So I ask you: any other versioning strategies that you prefer when you want to lessen the impact of production modifications? How do you like organizing your solution structure? If you only have to make a slight change, how do you prevent the rebuild of every dependent project?

Technorati Tags: BizTalk