Building dynamic activities in Workflow foundation 4

Right before I left for vacation I worked on a custom activity for our automated build process. It was an interesting experience I must say. I needed to produce an activity that contained partially fixed content, but that also allowed a developer to design a part of the body using the Visual Studio Workflow designer.
As it turns out there are a lot of options to build such an activity and each has its own features and limitations. In this post I will show you the various options and what each option gives you in terms of possibilities.
This first post is part of a series, that I will be posting in the coming few weeks. The reason you ask? Well it’s just too much to cover in a single post.
What are dynamic activities
In essence dynamic activities are components that don’t yet have an implementation at design time. There are some variations on this concept, but all of them share this concept.
Dynamic activities are useful for cases where you need to vary the implementation and/or arguments based on the user’s input or certain system conditions, such as the number of processors available.
Building a dynamic System.Activities.Activity based activity
There are three ways in which you can create a dynamic activity. The first method is to write an activity that derives from System.Activities.Activity, another method is to write a NativeActivity derived class. The third and last option is to create a new activity that derives from DynamicActivity. All of these options have different features and limitations and it’s important to know the difference between these options, because it has a profound impact on what value you can deliver to a developer using the activity you created.
In this post I will only talk about creating a dynamic activity using System.Activities.Activity as the base class. The others will be covered in subsequent posts.
Using Activity as a base type is the easiest way to create a dynamic activity. To create a new dynamic activity using this method you need to create a new class with the following contents.
1: namespace DynamicActivitiesSamples
2: {
3: /// <summary>
4: /// Dynamic activity based on the System.Activities.Activity base class
5: /// </summary>
6: public class DynamicActivity1: Activity
7: {
8: /// <summary>
9: /// Gets or sets a value indicating whether use extended version of the activity.
10: /// </summary>
11: /// <value><c>true</c> if the extended version should be used; otherwise, <c>false</c>.</value>
12: public bool UseExtendedVersion { get; set; }
13:
14: /// <summary>
15: /// Initializes a new instance of the <see cref="DynamicActivity1"/> class.
16: /// </summary>
17: public DynamicActivity1()
18: {
19: Implementation = () => CreateBody();
20: InitializeVisualBasicSettings();
21: }
22:
23: /// <summary>
24: /// Creates the body of the activity.
25: /// </summary>
26: /// <returns></returns>
27: private Activity CreateBody()
28: {
29: Sequence rootSequence = new Sequence();
30: rootSequence.Activities.Add(new WriteLine
31: {
32: Text = "Sample dynamic activity",
33: DisplayName = "Write custom message"
34: });
35:
36: if (UseExtendedVersion)
37: {
38: rootSequence.Activities.Add(new WriteLine
39: {
40: Text = "Extended sequence part",
41: DisplayName = "Write custom message"
42: });
43: }
44:
45: return rootSequence;
46: }
47:
48: private void InitializeVisualBasicSettings()
49: {
50: VisualBasicSettings settings = new VisualBasicSettings();
51:
52: // Add a sample import
53: settings.ImportReferences.Add(new VisualBasicImportReference() {
54: Assembly = "System.dll",
55: Import = "System"
56: });
57:
58: VisualBasic.SetSettings(this, settings);
59: }
60: }
61: }
Notice that the constructor assigns a lambda expression to the Implementation property, which calls the CreatedBody method. When the runtime instantiates the activity, it will invoke the Implementation Func<T> instance to create the implementation of the activity.
The CreateBody method in this case will return a new sequence containing a WriteLine activity. Normally you would create a new activity in XAML and design it using the Visual Studio 2010 workflow designer. This is not possible when you create a dynamic activity, but you can instantiate any activity in code that you can instantiate in XAML, it’s just more work.
The final interesting bit is the CreateImplementationSettings method. This method is used to configure an important part of the VB.NET subsystem used by the workflow runtime. You need this bit if you’re going to use custom types in arguments and variables. The CreateImplementationSettings method tells the runtime which namespaces are to be imported into the VB.NET parser when evaluating the VB expressions that are used in the implementation of the activity.
Building a dynamic activity using this method is specifically meant for cases where you need to compose the body of the activity from bits that are added externally, for example by letting a developer design the body of the activity. The options for dynamic arguments etc. are limited, as in there are none. If you need to add custom arguments based on input provided by the developer in the Visual Studio designer, you will need to use the DynamicActivity.
The features you well get using this technique
Creating a dynamic activity based on System.Activities.Activity is very basic, you won’t get a whole host of features. It does however offer a very easy to use method of varying the implementation of the activity based on conditions you put in the activity.
Limitations imposed by this design
Using System.Activities.Activity as the base for your dynamic activity means that you need to express the implementation of the activity as a single activity tree. You can’t mix it with imperative code. For example, it’s not possible to execute a piece of C# code, schedule an activity from that code and execute some C# code after the scheduled activity is completed.
You will also need to keep in mind that you can’t dynamically add arguments to the activity. This is only possible using the DynamicActivity base class, which I will discuss in the next post.
Conclusion
I’ve found working with Workflow Foundation 4 a lot more straightforward than working with the previous edition. Especially when it comes to the various options you have to build custom activities.
Okay, I have to admit here that this is not your typical Workflow Foundation development topic. I still think it’s good for people to know their options when it comes to custom activity development. So I hope you have found this post useful.
In the next post I will be talking about developing dynamic workflow activities based on the DynamicActivity base class.