Thursday, December 07, 2006 2:08 PM
bart
WF - Hello World via the Command Line (wfc.exe explained)
Introduction
A reader of mine noticed I'm using Visual Studio 2005 as the tool to create all of my Windows Workflow Foundation related samples, instead of taking my favorite minimal command-line approach to create basic samples. So here it is today: a simple Hello World demo of WF using the command-line.
Please welcome WFC
Just like csc.exe is the C#'s programmer best friend, wfc.exe plays that role for WF programmers. Basically it turns a .xoml file (which stands for eXtensible Object Markup Language) into a .dll assembly file representing the workflow you've designed. Below you can see a simple demo.xoml file:
<SequentialWorkflowActivity x:Name="Demo" x:Class="FooBar.Demo"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<CodeActivity x:Name="sayHello" ExecuteCode="sayHello_ExecuteCode">
<x:Code>
<![CDATA[
void sayHello_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello World");
}
]]>
</x:Code>
</CodeActivity>
</SequentialWorkflowActivity>
This simple sample can be compiled into a .dll file by invoking the following:
>wfc demo.xoml
In this case, we've been using a CDATA section to put the code inline between the XOML definition. Another approach would be to put the following in the demo.xoml file:
<SequentialWorkflowActivity x:Name="Demo" x:Class="FooBar.Demo"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<CodeActivity x:Name="sayHello" ExecuteCode="sayHello_ExecuteCode" />
</SequentialWorkflowActivity>
and to create another file called demo.cs:
using System;
namespace FooBar
{
partial class Demo
{
void sayHello_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello World");
}
}
}
which can be compiled using:
>wfc demo.xoml demo.cs
Notice the use of the partial keyword in the class definition. In the end, the .xoml file is a partial definition of the workflow class, so the .cs file is another part of it and has to be marked as "partial". Both compilations will yield the same assembly:
Using the assembly in a host application is another concern of course. Basically you just have to compile the following piece of code with a reference to the demo.dll file generated above:
using System;
using System.Threading;
using System.Workflow.Runtime;
namespace FooBar
{
class Hello
{
public static void Main()
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(FooBar.Demo));
instance.Start();
waitHandle.WaitOne();
}
}
}
}
which might be a little difficult to add the reference to the System.Workflow assemblies which reside in the GAC. A more convenient demo approach is to merge the host application and the code-behind for the workflow into one single .cs file, like this:
using System;
using System.Threading;
using System.Workflow.Runtime;
namespace FooBar
{
class Hello
{
public static void Main()
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(FooBar.Demo));
instance.Start();
waitHandle.WaitOne();
}
}
}
partial class Demo
{
void sayHello_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello World");
}
}
}
Now compile this file (demo.cs) together with the .xoml file, as follows:
>wfc /target:exe /r:System.Xml.dll demo.xoml demo.cs
MsBuild style
There's of course another approach that leans more towards Visual Studio 2005 compilation, i.e. using MsBuild. Assuming you have a file called demo.xoml:
<SequentialWorkflowActivity x:Name="Demo" x:Class="FooBar.Demo"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<CodeActivity x:Name="sayHello" ExecuteCode="sayHello_ExecuteCode">
<x:Code>
<![CDATA[
void sayHello_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello World");
}
]]>
</x:Code>
</CodeActivity>
</SequentialWorkflowActivity>
and a file called hello.cs:
using System;
using System.Threading;
using System.Workflow.Runtime;
namespace FooBar
{
class Hello
{
public static void Main()
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(FooBar.Demo));
instance.Start();
waitHandle.WaitOne();
}
}
}
}
you can create a .csproj build file that contains this:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RootNamespace>FooBar</RootNamespace>
<AssemblyName>Demo</AssemblyName>
<OutputPath>.</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Workflow.Activities" />
<Reference Include="System.Workflow.ComponentModel" />
<Reference Include="System.Workflow.Runtime" />
</ItemGroup>
<ItemGroup>
<Compile Include="Hello.cs">
<DependentUpon>demo.xoml</DependentUpon>
<SubType>Component</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="demo.xoml"/>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.0\Workflow.Targets" />
</Project>
which can be built using:
>msbuild
Enjoy command-line compiling WF-apps (for demo purposes only I hope)!
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks
Filed under: Windows Workflow Foundation (WF), .NET Framework 3.0 (WinFX)