How should you use WF4 and WCF with ASP.NET?
For this post I’ve created a really simple workflow and WCF service that delay for a specific amount of time and then return a value. Then I created an ASP.NET page that I can use to invoke the workflow and WCF service to test their behavior
The Workflow Definition
First off – let’s get one thing straight. When you create a workflow, you are creating a workflow definition. The workflow definition still has to be validated, expressions compiled etc. and this work only needs to be done once. When you hand this workflow definition to WorkflowInvoker or WorkflowApplication it will create a new instance of the workflow (which you will never see).
To make this clear, in this sample I have a workflow file SayHello.xaml but I named the variable SayHelloDefinition.
The Easy Way
If you want to do something really simple, you can just invoke workflows and services synchronously using WorkflowInvoker
Likewise you can invoke the WCF service synchronously
With the default delay of 1000ms this page will take about 2.5 seconds to load. 1 second for the workflow, 1 second for the WCF service and .5 seconds for everything else.
The Fast Way
If you are going to write code that runs on a server you should get used to writing async code. Yes I know it is generally a pain and more complex but what can I say… the result is far better.
Step 1 – Tell ASP.NET you want to do Async
ASP.NET won’t allow async work unless you set the Async directive.
Step 2 – Use the ASP.NET Synchronization Context
In this simple workflow I’m not using persistence or bookmarks (which would make the code slightly different if I did). One of the more confusing elements of doing Async work is that as you search the web you will see the history of how async was done in the past and you might get confused. In fact I found that it is quite difficult to pin down what the correct method is today.
What you want to do is to tell the Workflow Runtime that you are working with a SynchronizationContext from ASP.NET. Once you have done this, you can inform ASP.NET (via the context) when your operation begins and ends. This code gets a little tricky but follow along.
Step 3 – Configure your Service Reference for Async Operations
When you add a Service Reference the default is to not generate async operations.
Step 4 – Call your Service Async
Now you have a super-charged proxy that can do async. There are two methods for async the old APM (Begin/End) and the newer Event based async model (EPM). In this code I’m using the EPM model. Note that I don’t have to call OperationStarted/Completed because WCF will do it for me.
Step 5 – Test Your Service
I’ve enabled the ASP.NET Page Trace on my service so we can see what is happening.
As you can see we started the workflow and the service call on thread 37. Then ASP.NET was able to do some additional work before our workflow and service call which completed later. ASP.NET will wait on both of these to complete before it finishes rendering the page and returning to the caller.
With Workflows you
- Set the WorkflowApplication.SynchronizationContext to the ASP.NET synchronization context
- Call OperationStarted/Completed to let ASP.NET know when the workflow is done
With WCF you
- Configure your service reference for async operations
- Use async operations in your code
- Don’t have to worry about SynchronizationContext
Twitter: @ronljacobs https://twitter.com/ronljacobs