Monday, February 9, 2009

Declarative Workflow

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:
kick it on DotNetKicks.com
Save to delicious 0 saves

No comments:

Post a Comment