The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

Versioning long running workfows part 1
Part 1
Part 2
Part 3
Part 4

 

One of the cool features of Windows Workflow Foundation is that it allows long  running processes. And not just long running as in a few minutes but really long running as in a few years Smile. This is possible true the use of the SqlWorkflowPersistenceService, or in fact any derived class from WorkflowPersistenceService, which is going to save the state of a workflow to disk when it is not actually busy.

So that is pretty cool but it is kind of unlikely that your programs are not going to change over a year so in all likelihood  you are going to be deploying newer versions of your assemblies while there are multiple workflow's active. In order to allow multiple versions of a workflow to run we need to understand what is going on under the covers.

To demonstrate the behavior I am going to use a small project with the following layout. The WorkflowConsoleApplication1 is the host and is configured to use SqlWorkflowPersistenceService. The WorkflowLibrary1 is the project containing the actual workflow and this is the project we are going to version.

image

The main program is pretty simple and looks like this:

static void Main(string[] args)
{
    using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
 
        string connStr = @"Data Source=.\sqlexpress;Initial Catalog=WorkflowPersistence;Integrated Security=True";
        SqlWorkflowPersistenceService persistence = new SqlWorkflowPersistenceService(connStr,
            true, TimeSpan.FromSeconds(15), TimeSpan.FromMinutes(1));
        workflowRuntime.AddService(persistence);
 
        workflowRuntime.ServicesExceptionNotHandled += (sender, e) =>
            {
                Console.WriteLine(e.Exception.Message);
            };
 
        workflowRuntime.StartRuntime();
 
        WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Workflow1));
        instance.Start();
 
 
 
        Console.WriteLine("Press ennter to stop");
        Console.ReadLine();
 
        workflowRuntime.StopRuntime();
    }
}

Basically it sets up the SqlWorkflowPersistenceService, starts the runtime, starts a new workflow and waits for the user to terminate the program. It also prints any exceptions that might occur in a workflow runtime service like the SqlWorkflowPersistenceService.

image

The workflow is real simple. It just loops forever and prints a message that includes the assembly version number every 10 seconds.

What we are going to do is start this program so we have a first instance in the persistence store, update the workflow assembly to version two an have version 1 and 2 run side by side.

The WorkflowPersistenceService part.

The WorkflowPersistenceService actually persists, or dehydrates as it is called, a workflow using the binary serializer. This means that when it recreates, or dehydrates as this is called, the workflow instance it is done in a assembly version depended manner. So the first thing to be aware of is the standard .NET versioning behavior.

For a .NET assembly to be versionable the first prerequisite is that it has a string name. The rules are simple, no strong name = no versioning and the first assembly found will be the one that is used. Now there is a potential problem here because the binary serializer uses the most compact form possible and doesn't store field names, only their value. The object is responsible for reading the data from a stream in the correct order and size. No problem as long as the same type that was serialized is actually used to deserialize an object. But suppose a newer type is used that actually expects extra fields? Well it is going to try to read some data that is not actually there and the process is going to fail Sad.

Versioning assemblies is important!

So in order to be able to version the WorkflowLibrary1 assembly we need to add a strong name. This is done in the project settings on the Signing tab as follows:

image

When we run the application we can see from the following output that the workflow version 1 is running just fine Smile.

image

Once we have stopped the application its time to upgrade to version 2.0.0.0. Now I am not even going to make any changes to the workflow, all I am going to do is change the assembly major version number of the WorkflowLibrary1 project to 2. This is actually stored as part of the assembly and thus causes the project to recompile.

image

If we run the application again we are going to see the following output:

image

While version 2.0.0.0 of the workflow will run just fine version 1.0.0.0 cannot be loaded and the SqlWorkflowPersistenceService reports the following error via the WorkflowRuntime ServicesExceptionNotHandled event.

Could not load file or assembly 'WorkflowLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8afb6d596a769080' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

This error is the result of the binary serializer seeing that the workflow was dehydrated with version 1.0.0.0 of the WorkflowLibrary1 so it wants to load that version. And that is nowhere to be found as we only have version 2.0.0.0 which is not good enough.

Enabling side by side execution

The first ting we need to do is make sure we have both versions of the assembly WorkflowLibrary1 available. In order to do so we need to create a folder in the bin\Debug folder with the name Version_1_0_0_0. This is the folder where I am going to keep a copy of the WorkflowLibrary1.dll version 1.0.0.0.

image

Next we need to tell the .NET runtime where to look for version 1.0.0.0 of the assembly by adding this information to the app.config of our application. This is standard .NET material and in no way specific to Windows Workflow Foundation. The app.config looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="WorkflowLibrary1" publicKeyToken="8afb6d596a769080" />
        <codeBase version="1.0.0.0" href="Version_1_0_0_0/WorkflowLibrary1.dll"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

With both versions of the assembly and configuring the runtime so it knows where to find the first version of the assembly both versions of the workflow will run happily together Smile.

image

 

So how about the GAC?

In this example I use a private location to store multiple versions of the assembly but I could also have used the Global Assembly Cache, of GAC for short, to do this. Both mechanisms allow an assembly to be versioned so which is better? Normally the GAC should be used by assemblies used with multiple applications. In this case, and this is probably the case with most workflow assemblies, the WorkflowLibrary1 assembly only used by our host and not by other applications making a private location the proper place. That said there are certainly scenarios, like shared custom activity assemblies, where the GAC would be the proper place.

So are we all set?

No unfortunately not quite because there are some more issues that might crop up with versioning. So stay tuned for more Smile

 

Enjoy!

www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu

Published Wed, Sep 10 2008 5:46 by Maurice
Filed under: , , , ,

Comments

# re: Versioning long running workfows@ Thursday, September 11, 2008 8:25 AM

Hi,

Interesting read and fetched back a few memories.

I put a system together last year when Windows WF was pretty much just released.  I hit all sorts of problems with the versioning exceptions when I had to make tweaks to the workflow during testing, but didnt realise exactly why at the time.  As there were very few resources around to help me it was a case of having to roll my sleeves up and get under the covers to fully understand what was going on.

It wasnt until i had to make some further changes to the system once it was up and running that i fully got to grips with how the workflow runtime loaded the type for each instance.  My first impression was that the workflow item worked its way around the workflow so it didnt matter if you changed the workflow it would just work using the latest version - but this isnt the case.  Each instance is a copy of the workflow in a certain way of thinking.  

How i finished up getting around it was slightly different to yours as i didnt realise you could do the things you have with the web.config and setting references to assemblies.  

What i thought i needed to do was create a new copy of the workflow (at design time) and deploy both versions.  This was fine but the next issue i had was  how do i copy a workflow and make some changes.  Heindsight says this was a bad move but it didnt jump out at me at first.  Anyway.. I ended up copying the workflow xaml xml and changing the xaml to a new type - V2.  And this actually worked!  

Now i had old and new versions of the workflow and could make my changes and deploy.  

The next issue i came across was code that was hooked into the workflow, i.e. any services/classes that made use of the workflow.  You had to change the code to tell it what version of workflow to create, that was easy but then if you had referred to the workflow at any point in your classes, and this had been removed/changed then it would obviously break.  

Now i have more experience in everything .net, not just wwf i plan to revisit wwf and the issues above - so i shall keep an eye on your blog with interest on your next article.

As an aside ive not used wwf in a project since as i found the hosting part a large amount of work as i was hosting in IIS and i had a lot of considerations to think about - threading etc.  It is this that has put me off using it more as i think its a fantastic tool.  I am now about to look at sharepoint and how it uses the WF.  

Also id like to learn more about hosting mutliple types of workflow for multiple projects i.e. easier re-use and a single host deployment.  This would be really neat for what i would like to do with workflow.

by Damian

# Versioning long running workflows part 2@ Thursday, September 11, 2008 1:53 PM

Part 1 Part 2 In my previous post I demonstrated how to keep multiple versions of an assembly around

# Versioning long running workfows - The Problem Solver@ Thursday, September 11, 2008 1:57 PM

Pingback from  Versioning long running workfows - The Problem Solver

# re: Versioning long running workfows part 1@ Thursday, September 11, 2008 2:01 PM

Hi Damian ,

Good suggestion to do a few posts or an article about hosting.

by Maurice

# Versioning long running workflows part 2@ Thursday, September 11, 2008 2:09 PM

Part 1 Part 2 In my previous post I demonstrated how to keep multiple versions of an assembly around

# Versioning long running workfows part 3@ Tuesday, September 16, 2008 9:29 AM

Part 1 Part 2 In the first article of this series I demonstrated how to get multiple versions of a workflow

# Versioning long running workfows part 3@ Tuesday, September 16, 2008 10:03 AM

Part 1 Part 2 In the first article of this series I demonstrated how to get multiple versions of a workflow

# Versioning long running workflows part 4@ Monday, September 22, 2008 7:23 AM

Part 1 Part 2 part 3 In the previous blog posts we made sure we could have multiple versions of the same

# Versioning long running workflows part 4@ Monday, September 22, 2008 7:56 AM

Part 1 Part 2 Part 3 Part 4 In the previous blog posts we made sure we could have multiple versions of

# re: Versioning long running workfows part 1@ Saturday, October 04, 2008 7:43 PM

Thank you for this.