Both Windows Communications Foundation (WCF) and Windows
Workflow Foundation (WF) were released at the same time as part of the .NET 3.0
release. But even though they were released together, they didn’t really work
together. The main culprit here was Windows Workflow Foundation, which only
contains activities for connecting to and publishing workflows as web services.
This lack of WCF support was fixed in the .NET 3.5 release when the WF team
added two new activities. The first of these is the SendActivity, which enables
you to call WCF as well as standard web services. The second is the
ReceiveActivity, which enables a developer to publish a workflow as a WCF
service. In this first article I will take a look at how you can use the
SendActivity in your workflows. In a next article I will be taking a closer
look at the ReceiveActivity and the capabilities it has to offer.
Sending requests to remote services
When we want to send requests to a remote service, we can
use the SendActivity. Using the SendActivity is quite straightforward,
especially with a WCF service as the target. Because WCF is
backwards-compatible with the more traditional ASMX style web services, you can
also use the SendActivity to work with these services; however, as we will see,
this requires a bit more work, and using the InvokeWebServiceActivity can be
easier.
Calling Windows Communication Foundation services
The function of the SendActivity is to call a WCF service
from within a workflow. The best way to explain how to use it is by creating a
simple example. In this example I am using Visual Studio 2008, which comes with
the .NET 3.5 Framework. The first step is to create a new Visual Basic
Sequential Workflow Console Application (see Figure 1). Let’s call it
SimpleSend.

Figure 1. The New
Project dialog box to create the workflow application
When the project is created, it will automatically open the
default workflow, with the name Workflow1, in the designer. If you now open the
Toolbox and scroll to the bottom (see Figure 2), you will see a section named
Windows Workflow v3.5, which contains the two new activities.

Figure 2. The toolbox
showing the new Windows Workflow Foundation 3.5 activities
Before we go on, we first need to add a WCF service to call.
Let’s add to the solution a second project of type WCF Service Library, found
under the WCF tab, and call it SimpleService. This new project contains a very
basic WCF service with the name IService1 and a function GetData that takes an
integer as parameter and returns a string. This simple interface will do just
fine for the first sample, so just leave it as it is and build the solution.
To call this WCF service from our workflow, we need to add a
SendActivity to the workflow. The activity will show up displaying a red
exclamation mark at the right top indicating that it isn’t configured properly
yet (see Figure 3). The first thing to notice here is a difference compared
with the InvokeWebService activity that was released as part of the .NET 3.0
Framework. When an InvokeWebService activity is dropped on a workflow, it
displays the “Add Web Reference” dialog to add the required web reference.

Figure 3. Adding a
SendActivity to the new workflow
In the case of the SendActivity the “Add Service Reference”
dialog box used to add a WCF service doesn’t automatically appear. As mentioned
previously, the SendActivity isn’t configured properly, and the first thing it
needs is a service operation to call. This is set using the
ServiceOperationInfo property, but before we can do this, we need to add the
service reference ourselves. To do so, right-click the SimpleSend project in
the Solution Designer and select “Add Service Reference…” to add this
reference. In the dialog box (see Figure 4), click Discover to search for the
SimpleService in our solution. When we expand the service in the services tree,
Visual Studio will automatically start the new WCF service host, named
WcfSvcHost. This service host is similar to the simple web server included with
Visual Studio to make ASP.NET development easier. It means you can create a WCF
assembly without having to worry about hosting it while developing. Next,
change the namespace to SimpleService and click OK to add the reference.

Figure 4. Adding a
reference to the WCF SimpleService
Having added the service reference, we can now configure the
SendActivity itself. Click the button behind the ServiceOperationInfo in the
property sheet to specify the service operation to execute. This will show an
empty “Choose Operation” dialog box. To select an operation, we first need to
import the service interface using the Import… button. Clicking this Import…
button will display the type browser (see Figure 5). Select the IService1
interface and click OK. Once we have done this the “Choose Operation” dialog
box will show the two operations available in the IService1 interface (see
Figure 6). Select the GetData operation and click OK.

Figure 5. The type
browser used to select the WCF interface

Figure 6. The Choose
Operation dialog box
At this point the SendActivity knows what it is going to
call and will display the service operation parameter and return value in the
property sheet, as you can see in Figure 7. But the red exclamation mark
indicates we aren’t done with the configuration yet. While we have specified
what to call, we still need to specify where to call this service. Specifying
where to call the service is done using the ChannelToken property. Once we
specify a name for the service token (I am using Service1Token in this
example), a plus sign appears before the property name and we can expand it.
Doing so will show the EndpointName, which is what we need to add. This
EndpointName must point to an endpoint defined in the application configuration
file. This endpoint was added when we set the service reference to our WCF
service. In this case our endpoint was added with the name
WSHttpBinding_IService1, so that is what we need to specify. Once this is done,
we are almost ready to run our workflow; the only thing left is to add the
parameter and do something with the return value. Both the parameter and return
value show up in the property sheet, but that is actually a designer trick, as
there are no properties with these names.

Figure 7. The WCF
service parameter and return value.
Sometimes you might want to be more dynamic with the
location of the service called than storing it in the application configuration
file. In that case we can use the CustomAddress property to set the address of
the service dynamically at runtime.
In the case of the parameter, the value property in the
property sheet, we can either add a fixed value or specify a property whose
value should be passed. Passing a fixed value is easy—just type it into the
property sheet—but using a workflow property is more common. To do this we use
something called property binding. Property binding is a very powerful and
simple-to-use feature found both in Windows Workflow Foundation and in Windows
Presentation Foundation. To bind the value to send to a workflow property,
click the “…” button behind the value in the property sheet. This will display
the “Bind ‘value’ to an activity’s property” dialog box (see Figure 8) where
you can either select an existing or add a new property to bind to. As we don’t
have a property yet, we need to add a new one on the “Bind to new member” tab.
For this example, enter a name of TheValue, select “Create Property,” and click
OK to create the new property. Another way to add property bindings quickly for
all bindable properties is to select the option “Promote Bindable Properties”
from either the context menu or the commands at the bottom of the property
sheet. This action will generate workflow dependency properties for all the
activities’ bindable properties, including the BeforeSend and AfterResponse
handlers, and bind to these new properties.

Figure 8. Create a
new property binding
We also need to create a property binding for the service
operation return value named “(ReturnValue)” in the property sheet. Creating
this is done in exactly the same way as the value parameter; use TheResult as
the property name.
The SendActivity exposes two events we can use to set the
parameter we pass in and display the result returned. The first is the
BeforeSend event, which is fired, as the name suggests, before the WCF service
operation is called. The second event is named AfterResponse and is called
after the result is returned from the WCF operation. Listing 1 shows the two event
handlers used. Note that I use a Console.ReadLine to enable us to read the
output when the workflow is run. Please keep in mind that adding a blocking
statement like this inside of a workflow event is normally not a good practice
and should be avoided in a real workflow.
Private Sub BeforeGetData( _
ByVal sender As System.Object, _
ByVal e As System.Workflow.Activities.SendActivityEventArgs)
Me.TheValue = DateTime.Now.Second
End Sub
Private Sub AfterGetData( _
ByVal sender As System.Object, _
ByVal e As System.Workflow.Activities.SendActivityEventArgs)
Console.WriteLine("The result was '{0}'", Me.TheResult)
Console.ReadLine()
End Sub
Listing 1. The
SendActivity event handlers
Now we are ready to run the workflow, so go ahead and press
F5 to start it. Just like when we added the service reference, the WCF Service
Host automatically starts to host our web service. Once the workflow has
started, it will call the WCF service and the output will look something like
Figure 9. Note that the exact output might be different, as the value passed in
depends on the current time.

Figure 9. Running our
SimpleSend workflow
Using the SendActivity with a Web Service
Because WCF is backwards-compatible with ASMX-style web
services, it is also possible to use the SendActivity to call a “traditional”
web service. Let’s create a new project, called AsmxSend, to demonstrate how to
do this. The first steps are the same, so create a new Sequential Workflow
Console Application named AsmxSend. This time, add a second project to the
solution, but use an ASP.NET Web Service Application, which is found under the
Web tab. Let’s name the project AsmxService. This adds a new web service with
its default HelloWorld web method. To let us compare this with the WCF service
we just added, we are going to add the same GetData() function we used in that
sample; this function can be found in Listing 2.
<WebMethod()> _
Public Function GetData(ByVal value As Integer) As String
Return String.Format("You entered: {0}", value)
End Function
Listing 2. The
GetData function used in the web service
As before, we need to add a service reference to the web
service (see Figure 10). Make sure to add a service reference and not a Web
Reference as found at the bottom under the advanced service reference settings.
The reason we do not want to add a web reference is that this generates a
different type of proxy, and the SendActivity needs a WCF-style proxy object to
work with. For this example, use AsmxService as the namespace when adding the
service reference.

Figure 10. Adding a
service reference to an ASMX web service
Once we have added the service reference to the AsmxService
we can add a SendActivity to the workflow in our AsmxSend project. Configure
the SendActivity ServiceOperationInfo as before, selecting the Service1Soap as
the type and GetDate as the operation to use. We also need to specify the
ChannelToken and the EndpointName. This time the Endpoint added to the
app.config is named “Service1Soap”.
Just like before, we need to add property bindings for the
operation parameter and return value; use the same names as before, TheValue
and TheResult. Although we don’t see any difference in the dialog box when
adding the property bindings, something very different happens. The operation
parameter is of type integer, and before, when we added a service reference to
the WCF service, a property of type integer was added. But in this case, when
using an ASMX web service, a property of type GetDataRequest is also created.
This object of type GetDataRequest contains a single field, named Body, of type
GetDataRequestBody, and this body in turn contains the actual integer value
passed. The same is true with the return value, which is of type string. In the
WCF service reference the type of TheResult was string, but with the ASMX
service reference this becomes a property of type GetDataResponse which in turn
contains a Body field of type GetDataResponseBody. This GetDataResponseBody
finally contains the actual string value retuned in the GetDataResult field.
So, while the code might be slightly more verbose, calling ASMX-style web
services is just as easy as calling WCF services (see Listing 3).
Private Sub BeforeGetData( _
ByVal sender As System.Object, _
ByVal e As System.Workflow.Activities.SendActivityEventArgs)
Me.TheValue = New AsmxService.GetDataRequest
Me.TheValue.Body = New AsmxService.GetDataRequestBody
Me.TheValue.Body.value = DateTime.Now.Second
End Sub
Private Sub AfterGetData( _
ByVal sender As System.Object, _
ByVal e As System.Workflow.Activities.SendActivityEventArgs)
Console.WriteLine("The result was '{0}'", _
Me.TheResult.Body.GetDataResult)
Console.ReadLine()
End Sub
Listing 3: The code
used when calling an ASMX style web service.
One unexpected behavior is that we now see an error
appearing in the workflow; see Figure 11 for an example. This error claims that
the type of the property binding on TheResult is not the correct type. In fact,
as the message claims, both are of type AsmxSend.AsmxService.GetDataResponse
and the property binding is correct. So ignoring this error and running the
workflow will result in the expected behavior.

Figure 11. The
incorrect error message
Conclusion
As we have seen, using the Workflow Foundation SendActivity
to talk to either a WCF or an ASMX service is quite straightforward. Working
with an ASMX web service is a bit more work, and as there is little or no
benefit of the SendActivity over the CallWebServiceActivity, using the latter
might be more appropriate. This, however, is just half the story, as .NET 3.5
also comes with a ReceiveActivity and its job is to expose a workflow as a WCF
service, similar to what the WebServiceInputActivity/WebServiceOutputActivity
pair allowed us to do as an ASMX style web service. In the next article I will
be taking a closer look at this ReceiveActivity.
About Maurice de
Beijer
Maurice de Beijer is an independent software consultant
specializing in Workflow Foundation and .NET in general. He has been awarded
the yearly Microsoft Most Valuable Professional award since 2005. Besides
developing software, Maurice also runs the Visual Basic section of the Software
Development Network, the largest Dutch .NET user group. Maurice can be reached
through his web sites, either www.WindowsWorkflowFoundation.eu
or www.TheProblemSolver.nl, or by
emailing him at Maurice@TheProblemSolver.nl.