Introduction
One way to make a WCF service operation and a WF workflow communicate with each other
is by adding a HandleExternalEvent or CallExternalMethod activity to a workflow.
A HandleExternalEvent activity is much like an ordinary event handler. The workflow
just waits for a certain event to be triggered by the service. The event arguments
are used as parameters passed to the workflow.
The CallExternalMethod activity does the opposite. It can call a method on a local
service, which is accessible to the WCF service operation. This activity could
be used by the workflow to return values to the service.
To illustrate this, let’s create a very simple client-server application where the
server provides a WCF service that accepts a string input and returns the string
in reverse, which is actually done by a workflow. Take note that the mentioned
activities need not be at the start or at the end of a workflow.
Creating the Workflow Service
Create a new WCF service application project. The following files are automatically
generated: IService1.cs, Service1.svc and Web.config. Rename all references of Service1 to the
desired name of the service, which is StringService in this example. The following
listing shows the WCF service interface.
[ServiceContract]
public interface IStringService
{
[OperationContract]
string ReverseString(string stringToReverse);
}
We need to two things before we can implement this interface: the workflow and a
service that facilitates data exchange between the service and workflow.
The Workflow
Add a new workflow project to the solution. You may add either a state-machine or
sequential workflow library. A sequential workflow library will suit our needs
of our example so add a project of this type. We can name the project StringWorkflows.
Let’s rename Workflow1 to ReverseStringWorkflow. The following screenshot shows
the workflow.

The activity labeled handleReverseStringStarted is the HandleExternalEvent activity.
When this workflow is started, it will still wait for a certain event to be raised
by the WCF service. This event is specified as a property of the HandleExternalEvent
activity. The string to be reversed is passed from the service to the workflow
using this event.
The activity labeled callSetReversedString is the CallExternalMethod activity. This
activity calls a method found in the data exchange service. We would return the
reversed string using this activity.
The reverseString Code activity represents the business logic code of our example.
It is responsible for reversing the string.
The Data Exchange Service
You might have first tried creating a workflow and added HandleExternalEvent and
CallExternalMethod activities. However, you will notice that both activities
need an interface type marked with an ExternalDataExchangeAttribute. We’ll have
to create the interface first. Let’s create another project of type class library
called LocalServices where we can add the interface and implementation. Be sure
to add references to required assemblies. The interface is shown in the code
below.
[ExternalDataExchange]
public interface IReverseStringLocalService
{
event EventHandler<ReverseStringStartedEventArgs> ReverseStringStarted;
void ReverseString(Guid instanceId, string stringToReverse);
void SetReversedString(string reversedString);
}
The ReverseStringStarted event is supplied as one of the required property of the
HandleExternalEvent activity as explained earlier. The ReverseStringEventArgs
is defined below.
[Serializable]
public class ReverseStringStartedEventArgs : ExternalDataEventArgs
{
public ReverseStringStartedEventArgs(Guid instanceId, string stringToReverse)
: base(instanceId)
{
StringToReverse = stringToReverse;
}
public string StringToReverse { get; private set; }
}
The ReverseStringStartedEventArgs class must inherit from ExternalDataEventArgs class
to be used in the HandleExternalEvent. It must also be marked as Serializable because an instance must be serialized before
it is passed to the workflow. I presume that this is done since the workflow
can be persisted to a persistence store.
Another requirement is that the ReverseStringStartedEventArgs’ constructor must call
the base class’ constructor, which accepts a workflow instance’s id as its parameter.
This is used so that only the workflow instance with that id is notified of the
event. Note that there could be many workflow instances waiting for the same
event.
Now let’s take a look at how the interface is implemented.
[Serializable]
public class ReverseStringLocalService : IReverseStringLocalService
{
public event EventHandler<ReverseStringStartedEventArgs> ReverseStringStarted;
public string ReversedString { get; private set; }
void IReverseStringLocalService.ReverseString(Guid instanceId, string stringToReverse)
{
if (ReverseStringStarted != null)
{
ReverseStringStarted(this, new ReverseStringStartedEventArgs(instanceId, stringToReverse));
}
}
void IReverseStringLocalService.SetReversedString(string reversedString)
{
ReversedString = reversedString;
}
}
The ReverseString() method just raises the ReverseStringStarted event and is called
by a WCF service operation.
On the other hand, the SetReversedString() method is called by a WF workflow to return
the reversed string. The property ReversedString is set in this method, which
is then accessed by the WCF service operation.
It is not required to mark the class as Serializable if you do not intend to pass
the instance to the workflow. In this case, I’m passing this as the sender parameter.
Setting Activity Properties
Now that we have an interface marked with ExternalDataExchangeAttribute, we can now
set the required properties of the HandleExternalEvent and CallExternalMethod
activities. Let’s start first with the HandleExternalEvent activity.
First, add a reference to the LocalServices project to the StringWorkflows project.
The following screenshot shows the properties of the HandleExternalEvent activity.
The InterfaceType and EventName properties are required.

Set the InterfaceType to the IReverseStringLocalService like the one shown below.
After this, choose the ReverseStringStarted event as the value of the EventName
property.

You will see additional properties when the EventName property is set. These are
e and sender. The property e refers to the event arguments, which contains the
string to be reversed. The sender is the object which raised the event. Since
we only need the string to reverse, bind e to a field or property. This is shown
in the following screenshot.

We have to do the same for the InterfaceType property of the CallExternalMethod activity.
Afterwards, set the MethodName property to the SetReversedString() method. Notice
that once again, an additional property is added which is called reversedString.
Bind this to a field or property.
The following code listing shows the workflow’s code-behind. I’ve already added the
OnReverseString() method’s implementation.
public sealed partial class ReverseStringWorkflow : SequentialWorkflowActivity
{
public LocalServices.ReverseStringStartedEventArgs reverseStringStartedEventArgs = default(LocalServices.ReverseStringStartedEventArgs);
public String reversedString = default(System.String);
public ReverseStringWorkflow()
{
InitializeComponent();
}
private void OnReverseString(object sender, EventArgs e)
{
reversedString = new string(reverseStringStartedEventArgs.StringToReverse.ToCharArray().Reverse().ToArray<Char>());
}
}
Implementing the WCF Service Interface
The following code listing shows the implementation of the WCF service interface
shown earlier.
public class StringService : IStringService
{
public string ReverseString(string stringToReverse)
{
using (WorkflowRuntime runtime = new WorkflowRuntime())
{
AutoResetEvent waitEvent = new AutoResetEvent(false);
ExternalDataExchangeService dataExchangeService = new ExternalDataExchangeService();
runtime.AddService(dataExchangeService);
ReverseStringLocalService localService = new ReverseStringLocalService();
dataExchangeService.AddService(localService);
runtime.WorkflowCompleted +=
(
(object sender, WorkflowCompletedEventArgs e) =>
{
waitEvent.Set();
}
);
WorkflowInstance instance = runtime.CreateWorkflow(typeof(ReverseStringWorkflow));
runtime.StartRuntime();
instance.Start();
localService.ReverseString(instance.InstanceId, stringToReverse);
waitEvent.WaitOne();
return localService.ReversedString;
}
}
}
First, we need to create a WorkflowRuntime instance. This manages execution of workflows.
In able to use the HandleExternalEvent and CallExternalMethod activities in our
workflow, we need to create an instance of an ExternalDataExchangeService class
and add it as a service of the workflow runtime.
After this, we can add the instance of our ReverseStringLocalService as a service
of the ExternalDataExchangeService instance. All that’s left to do is start the
workflow runtime, start the workflow instance and call our ReverseString() method.
However, since we are triggering an event, the WCF service operation may end before
the workflow completes. That’s why we have to use an AutoResetEvent and subscribe
to the WorkflowCompleted event of the runtime.
The Client
I wouldn’t elaborate more on how to use the WCF service in the client application.
Just add a service reference and call the ReverseString() method on the service
proxy. The following screenshot shows the application UI.

The Visual Studio 2008 example can be downloaded here.
Remarks
A problem that I encountered when I used the example I presented is how to throw
exceptions from the workflow, since I want to notify the client of any exception
that may have occurred. This is because of how exceptions are notified to the
WCF service, which is by using an event. It might be possible to re-throw an
exception but I ended up using a ReceiveActivity instead because it is much cleaner.