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)!

kick it on DotNetKicks.com

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

No Comments