Today, I began to experiment on MS WF.
I find very useful the possibility to load at runtime a xaml file of my personal workflow.
To reach my goal I create two project with VS 2008 to test my solution:
- A console project which is the entry point of my application;
- A workflow library where put my custom activity and sequence workflow.
In my workflow library I add a xaml file where I put only my custom simple sequence with only one custom activity that print a "Hello world" (see the figure below).
Remember that the custom activity must be tagged as [Serializable].

My xaml file hasn't the code behind because I built my workflow in declarative manner. If you take look at xml you could see:
<SequentialWorkflowActivity x:Name="Workflow1"
xmlns:ns0="clr-namespace:MyWorkflowLibrary.Task;
Assembly=MyWorkflowLibrary, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<ns0:HelloWorldTask x:Name="helloWorldTask1" />
</SequentialWorkflowActivity>
Note that I remove the x:Class attribute in SequentialWorkflowActivity. I do that because I haven't the compiled class in the code behind. In namespace attribute I add the reference to the assembly container of my activity, because this will be resolved at runtime.
The console application "Main" looks something like this:
static void Main(string[] args)
{
// Here, I read my xaml file containing my declarative workflow
var xmlReader =
new XmlTextReader(
new StringReader(
File.ReadAllText(
@"C:\Users\simonem\Documents\Visual Studio 2008\Projects\
TestWorkflow\MyWorkflowLibrary\HelloWorld.xoml")));
var runtime = new WorkflowRuntime();
runtime.StartRuntime();
runtime.WorkflowCompleted += delegate
{
Console.WriteLine("WorkFlow completed");
Console.Read();
};
try
{
var instance = runtime.CreateWorkflow(xmlReader);
instance.Start();
}
// Here I manage potential workflow validation exceptions
catch(WorkflowValidationFailedException wfve)
{
var errorValidation = string.Empty;
foreach (var error in wfve.Errors)
{
// StringBuilder is better...
errorValidation += Environment.NewLine + error.ErrorText;
}
Console.WriteLine(errorValidation);
}
// General exceptions
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}Troubleshooting:
- If during the program execution you receive an error such as "Could not deserialize object. The type 'clr-namespace:MyWorkflowLibrary.Task;.HelloWorldTask' could not be resolved. startIndex cannot be larger than length of string.Parameter name: startIndex" remember to specify the assembly reference in workflow xml code (see below):
<SequentialWorkflowActivity x:Name="Workflow1"
xmlns:ns0="clr-namespace:MyWorkflowLibrary.Task;
Assembly=MyWorkflowLibrary, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">- If you couldn't compile your solution and you receive the following error "Cannot compile a markup file which does not contain declaration of the new workflow type." you must change the build action on your xaml file from "Content" to "None".
References: