The other day I had to use Windows Workflow Foundation in legacy .NET 3.5. The goal was to address the scenario where the power user may upload valid XML files … in an Enterprise Application for different workflows, In other words to avoid hard coding the workflow activities in C# code. So I had to essentially address 2 objectives :
- The workflow should be loaded dynamically on the fly
- There might be more than one workflows.
So I came up a simple design where the power user may upload a XML file and may give nick names … basically a mini XML file management. Then in the Workflow management module I wrote down something not too different from the following C# code : Let’s start with a simple custom activity
Code Activity is great for a proof of concept or demos but here in WF 3, I think Custom Activity is better than just the code activities, because not only one may parameter-ize them but also they could be reused. I think you’d agree too, at the end of this quick blog post.
So, I had to use Visual Studio 2008 to modify this legacy application but you may use the latest-n-greatest ( and my favorite ) Visual Studio 2013 too ! … Or you want to exactly follow along change the .NET version to 3.5. ( I shall write another blog post for newer version of .NET 4.0 or 4.5 … I promise ! ) For this blog post demo, I started with basic Console Application, named it “WorkflowConsoleApplication3” and then added a new project called “WorkflowProject1” using the Empty Workflow Project Template. Like So : I’ve posted how Program.cs looks like for the console application at the end as it was untouched until end. Next, in the Work Flow Project that we created above, let’s add a new class called “WriteLine”. This is going to be our activity. So let’s inherit this class from System.Workflow.ComponentModel.Activity and make couple other changes as shown below :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Workflow.ComponentModel; namespace WorkflowProject1 { public class WriteLine : Activity { public string Text { get; set; } public ConsoleColor TextColor { get; set; } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { Console.ForegroundColor = TextColor; Console.WriteLine(Text); Console.ResetColor(); return ActivityExecutionStatus.Closed; } } }
Feel free to add such few other activities of your choice ( Like exporting some data to file, sending emails etc. ) in the same project or may be in the different project. Alright now you’re ready to create XML workflow definition ! So lets get back to the console application called “WorkflowConsoleApplication3” that we created in the beginning and let’s add XML file from ‘add new item’ window using Visual Studio. ( Did not worry to change the name from XMlFile1.xml … ) For the sake of this demo I created 3 activities for WriteLine as shown below :
<?xml version="1.0" encoding="utf-16"?> <SequentialWorkflowActivity x:Name="SequentialWorkflowActivity" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" xmlns:at="clr-namespace:WorkflowProject1;Assembly=WorkflowProject1,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> <at:WriteLine x:Name="a1" Text="Line 1" TextColor="Cyan"> </at:WriteLine> <at:WriteLine x:Name="a2" Text="Line 2" TextColor="Yellow"> </at:WriteLine> <at:WriteLine x:Name="a3" Text="Line 3" TextColor="Green"> </at:WriteLine> </SequentialWorkflowActivity>
Now if did notice in the XML above we are using a namespace called “xmlns:at” @ Line 7. What is ‘at’ ? … I just made that up AT are my initials 😉 But here is the important ( and sneaky ) step …
Do not forget to add project reference(s) to your assemblies which you want to use for activities in the XML
That said I need to add a reference to “WorkflowProject1” assembly to “WorkflowConsoleApplication3” project. And finally …. now is the time to make some changes to your Program.cs file as below : Notice that using WorkflowRuntime instance’s CreateWorkflow function we can feed the XML ( Line 22 ) that we just created and then Start() on Line 24 … would actually execute the workflow.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Workflow.Runtime; using System.Workflow.Runtime.Hosting; using System.Xml; using System.Threading; namespace WorkflowConsoleApplication3 { class Program { static void Main(string[] args) { using (WorkflowRuntime runtime = new WorkflowRuntime()) { AutoResetEvent waitHandle = new AutoResetEvent(true); XmlReader workflowReader = XmlReader.Create("..\\..\\XMLFile1.xml"); try { WorkflowInstance workflowInstance = runtime.CreateWorkflow(workflowReader); workflowInstance.Start(); waitHandle.WaitOne(); } catch (Exception ex) { throw; } Console.ReadKey(); } } } }
If I’d try to execute I might get a console window as shown below : There you have it ! … A very basic console application which can load and execute workflows on the fly !