Versioning long running workflows part 4

Part 1
Part 2
Part 3
Part 4

In the previous blog posts we made sure we could have multiple versions of the same workflow running side by side. This ability is one of the more powerful concepts of WF and a real must have for long running business applications.

A quick recap.

Always version your assemblies by giving them a strong name. Make sure the runtime can find each version of the assembly by pointing the CLR to the right version using the configuration\runtimeassemblyBinding\dependentAssembly\assemblyIdentity\codeBase in your App.Config (or Web.Config in the case of a web application). And make sure you use all types and interfaces from the same version as the workflow or, somewhat easier, stick to using basic CLR types when sending messages.

 

Great, but what about fixing bugs?

All the versioning is very nice but the simple fact is that sooner or later you are going to find a bug in your code and need to fix a specific assembly. In that case it would not be very nice if the workflow would keep on running with the buggy code. No in that case you would very much like to be able to dehydrate the worfklows and have them use the patched version of the assembly instead of the original one.

Fortunately this is easy to do, and again due to the standard binary serialization format Windows Workflow Foundation uses, completely standard .NET.

Again the trick is versioning the assembly and using the App.Config to redirect the runtime to the correct version. So just as I demonstrated in the previous posts I need to strongly sign the assembly. Next when we want to fix a bug in the assembly we need to update the version number and redirect the CLR to the new version. The last part is done using the following config file:

<?xml version="1.0" encoding="utf-8" ?>


<configuration>


  <runtime>


    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">


      <dependentAssembly>


        <assemblyIdentity name="WorkflowLibrary1" publicKeyToken="8afb6d596a769080" />


        <bindingRedirect oldVersion="1.0.0.0" newVersion="1.0.1.0"/>


      </dependentAssembly>


    </assemblyBinding>


  </runtime>


</configuration>



To demonstrate the effect the workflow below is started with a parameter that indicates the assembly version it was when started and prints this, long with the current assembly version, on the screen. as you can see the first workflow was started with version 1.0.0.0 but the assembly actually executing is updated to 1.0.1.0. In contrast the second workflow was created using the assembly 1.0.1.0.



image



So why bother to update the version number in the first place?



After all you could just leave the version number as is and replace the assembly. The main disadvantage is that it makes it harder to see which version was executing when a new bug report comes in. Was this the patched assembly and is the bug still there under specific circumstances? On other words: was the bug fix buggy[:(]. Or is the system still using the original assembly, and was the update not done correctly? Best just to avoid these kind of problems and make sure you can see which version either by looking at the assembly file properties or by having an error handler print all loaded assemblies, including version number.



 



Enjoy!



[f1]
[f2]

10 thoughts on “Versioning long running workflows part 4

  1. hey the link for part 3 is pointing to part 4. can you pls correct it so that we won’t miss the excellent flow and I don;’t want to miss part 3 and just jump to part 4.

  2. Maurice, thank you very much for this excellent series.

    Versioning workflow instances was a problem I had for a long time in my project and now I finally think it is doable, which I doubted before.

    One question tough: I have a custom tracking service defined in separate assembly, which is versioned. Recently I’ve updated it and suddenly old workflow instances, which were started with a previousversion of this service, stopped sending tracking information. I managed to solve this in not very elegant way, could you perhaps suggest some elegant solution? I just want to say that workflow version and tracking service version do not change at the same time.

    Thank you again

  3. Hi Ula,

    Is your custom tracking service actually using one of your custom types that you are using in the workflow? If so you are probably running into the same versioning issues where the variable used in the tracking service is of a different version the variable type in the workflow.

    One option is to use multiple tracking services, one for each version, but that doesn’t sound like a very workable solution. Another option is to stick to the native .NET types and only reference the data as Object and use reflection. Again not a very nice solution.

    Depending on the situation it would probably be best to add a class to your workflow assembly that does all the workflow data specific tracking work and create an object using reflection as I did with the external data service in part 2 (see the code in SendEvent2). Using this object do all the version specific work and return standard .NET types (like a Dictionary) with the data you need in the tracking service itself.

    Again not pretty but in line with what WF does.

    Maurice

  4. Hi Maurice,

    Thank you for your prompt answer. Issue with tracking service is similar to this post: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1565153&SiteID=1. Tracking service did not throw ClassNotFoundExcepton or CastException. It simple did not receive any events from the working workflow instance. As if tracking service was not there.

    Turned out, that workflow instance keeps somewhere very deep version number of tracking service that was used, when the instance was first created.

  5. Hi Maurice,

    In terms of making a fix to a particular version of a workflow, what if the fix incompatible with the version that has the bug? For example, if a new property was added, wouldn’t that make the it impossible to rehydrate the older workflow into the new workflow? Maybe I’m missing the whole point… will you please clarify for me?

    Thanks!
    -Zhou

  6. I have workflow service hosted in IIS invoked from asp.net.
    I have done side by side versioning using config file. Not used GAC. The is added to workflow service app.config and host web.config. If not added in host web.config the ‘Could not load assembly’ error was thrown.

    Now I get an error ‘The object with ID 37 implements the IObjectReference interface for which all dependencies cannot be resolved. The likely cause is two instances of IObjectReference that have a mutual dependency on each other.’ when an instance created with old version is rehrdrated.
    Please help.
    Thanks,
    Lisha

  7. I really enjoyed the series.. this is exactly the information I was looking for . we are doing a timesheet web application, using windows workflow for the approvals and such . thanks again

    ps: i had to firebug your css to be able read it, the dark gray background around the code is unviewable

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>