WF 4.5 added Versioning and Dynamic Updates to workflows.
The dynamic update process consists in 2 main steps:
- Defining the update, in terms of changes to the workflow definition. The output of this step is an Update Map
- Applying the Update Map to persisted workflow instances
Step A. above takes place in 3 substeps:
- Calling DynamicUpdateServices.PrepareForUpdate(Activity), where activity is the root activity of the workflow definition
- Making in-memory changes to the workflow definition
- Calling DynamicUpdateServices.CreateUpdateMap(Activity). This creates an update map, which is typically persisted, to be used sometime later to carry out step B. above.
Under the hood
Steps 1. – 3. above must be applied to the same in-memory workflow definition. This is because DynamicUpdateServices.PrepareForUpdate(activity) prepares that specific in-memory workflow definition for update, so the following call to CreateUpdateMap() must happen on the same in-memory instance.
PrepareForUpdate() annotates the in-memory workflow definition with information that will be used at a later time, when CreateUpdateMap() is called, to compute the delta. This is logically equivalent to creating an internal cloned workflow definition.
Note: PrepareForUpdate() and CreateUpdateMap() have overloads that take an ActivityBuilder as an argument, instead of an Activity. This simplifies the usage in conjunction with workflow definitions loaded from XAML (XamlServices.Load() returns an ActivityBuilder object, not an Activity), but it does not change the requirement that changes be applied to the in-memory workflow definition.
The Code Approach
Let’s focus now on step A.2 above, the in-memory changes to the workflow definition.
The easiest approach to the in-memory changes is to hard-code the changes in code. This link exemplifies this process. See, specifically, the “To update StateMachineNumberGuessWorkflow”, “To update FlowchartNumberGuessWorkflow” and | To update SequentialNumberGuessWorkflow” sections.
This approach works just fine. However, by hard-coding the changes into the program, it
- requires a different program for each new change
- requires a programmer to make the change, instead of a business owner
- may require a complex and hard-to-read sequence of statements in order to make a simple change to the workflow definition. This is especially true when the changes are made deep into the hierarchy of activities
In order to overcome these limitations, the changes would have to be made through the Workflow Designer, instead of being hard-coded. The requirement that the changes be made to the in-memory workflow definition rules out the Workflow Designer used in Visual Studio however: the WF Designer used in Visual Studio loads a workflow from a XAML file and saves the change to a XAML file, so it is not usable to make in-memory changes to a workflow definition.
The Re-hosted Workflow Designer Approach
The Workflow Designer, thankfully, is a reusable component that can be hosted in any process. Visual Studio just happens to be one host of Workflow Designer. By re-hosting the Workflow Designer in a custom host, we may be able to allow in-memory changes to the workflow definition through the Workflow Designer.
The Sample Code
The sample code attached to this post is general-purpose: the input is a workflow in XAML and the output, after the user makes changes to the workflow definition in the designer, are:
- the XAML file of the modified workflow
- the update map (XML file)
To use the sample:
- Load a workflow from the FIle…Open Workflow Definition menu item. DynamicUpdateServices.PrepareForUpdate() is called at this stage.
- Make the changes to the workflow definition in the designer. This includes adding activities, modifying existing activities, adding/removing variables and arguments.
- Save the workflow and create the update map using the File…Save and Create Update Map menu item. First, you can save the workflow definition to a .XAML file. Then, if you choose to save the update map, DynamicUpdateServices.CreateUpdateMap() is called and the update map is saved to an XML file.
This is how the program looks like, when a workflow definition is loaded:
A word of caution
A re-hosted Workflow Designer does not always offer the same user experience of the Workflow Designer in Visual Studio, because the Workflow Designer can be configured in many different ways.
For instance, the Services and Items of the Editing Context may be different, or configured differently. Also, a re-hosted Workflow Designer has some limitations. As far as dynamic update of workflows goes, though, these limitations should not be a roadblock.
You’ll also notice that the behavior of the Toolbox in the sample differs from that of Visual Studio:
- at startup, a pre-defined set of common activities is loaded in the Toolbox, grouped into a set of categories
- when a workflow definition is loaded, the activities of the workflow are added to a new category called Auto, displayed at the top of the toolbox
- it is possible to load additional activities by using the File | Add Activities in Assembly… menu item. All the activities in that assembly are added to a new category, named after the assembly, displayed at the bottom of the toolbox. You may want to load the System.Activities.dll assembly to see a broad range of activities (more than the Visual Studio toolbox shows)
- you can remove an entire category or an activity from the toolbox by right-clicking on them and selecting Remove
The sample provided here is not production-ready code: error handling is minimal, it does not have tracing or logging, and it has not been extensively tested.
All this said :-), if you find any issue with the sample, please let me know.