If you are building Windows Workflow Foundation (WF) applications today (and you aren't building Sharepoint Workflows) you should be using WorkflowServiceHost for your hosting environment. Period, end of discussion (oh - well we can have more decision about it - but its a fait accomplis at this point).
Especially if you are using WF to implement a service, using .NET 3.5 is a total no brainer.
I was doing so the other day using a StateMachineWorkflow hosted in IIS and I was getting an exception. The exception (which I found after I attached the debugger to IIS) was the dreaded (and pretty common) exception "QueueNotFound for queue X".
Now - if I was writing the hosting layer myself I would handle the WorkflowRuntime.WorkflowIdled event and introspect on the WorkflowInstance using WorkflowInstance.GetWorkflowQueueData method to see what queues where available at different points during the workflow to help figure out what the problem was. The problem was that I expected the Queue to be there at that paritcular point of execution, and I wanted to verify that fact using the WorkflowInstance.GetWorkflowQueueData method like this:
void WorkflowRuntime_WorkflowIdled(object sender, System.Workflow.Runtime.WorkflowEventArgs e){ReadOnlyCollection<WorkflowQueueInfo> queues;queues = e.WorkflowInstance.GetWorkflowQueueData();foreach (WorkflowQueueInfo qi in queues){Debug.WriteLine("QueueName : " + qi.QueueName);foreach (string actName in qi.SubscribedActivityNames){Debug.WriteLine("Activity subscribed: " + actName);}}}
This is code I end up writing in just about every Workflow application I build because it is just super useful to know what Queues a workflow is listening for at a particular time.
So here was my problem - since I was using WorkflowServiceHost implicitly through an svc file:
<%@ ServiceHost Service="WorkflowArtifacts.CalcWorkflow"Factory="System.ServiceModel.Activation.WorkflowServiceHostFactory" %>
using WorkflowServiceHostFactory, I had no place to get the WorkflowRuntime from the WorkflowServiceHost. If I was creating WorkflowServiceHost myself in code - I could use the following code to get the WorkflowRuntime:
//sh is the WorkflowServiceHostWorkflowRuntimeBehavior wrb = sh.Description.Behaviors.Find<WorkflowRuntimeBehavior>();wrb.WorkflowRuntime.WorkflowIdled += new EventHandler<System.Workflow.Runtime.WorkflowEventArgs>(WorkflowRuntime_WorkflowIdled);
Using the WorkflowRuntimeBehavior - I can get the WorkflowRuntime and then subscribe to the WorkflowIdled event - and thus be able to the get data I wanted for debugging my "QueueNotFound for queue X" exception. But alas - using the svc file I don't ever get access to the WorkflowServiceHost.
There is however a solution (at least one) - ServiceHostFactoryBase. One of the cool extensibility mechanisms with WCF you can take advantage of when hosting inside of IIS/WAS is creating your own ServiceHostFactory. By default with code-based services - WCF uses a ServiceHostFactory (which is a derived class from ServiceHostFactoryBase) to create the WCF ServiceHost (which derives from ServiceHostBase) for hosting a code-based service. For Workflow Services - they use a WorkflowServiceHostFactory (as you can see from my svc file) to create the WorkflowServiceHost.
Luckily (and I'm sure intention on the framework team's part) WorkflowServiceHostFactory isn't sealed. What this means is that I can create my own WorkflowServiceHostFactory class - change the Factory attribute in my svc file to point to my factory - and then insert the code I wanted to work with the WorkflowRuntime object.
Here's my WorkflowServiceHostFactory class:
public class MyWorkflowServiceHostFactory : WorkflowServiceHostFactory{public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses){ServiceHostBase sh = base.CreateServiceHost(constructorString, baseAddresses);//sh is the WorkflowServiceHostWorkflowRuntimeBehavior wrb = sh.Description.Behaviors.Find<WorkflowRuntimeBehavior>();wrb.WorkflowRuntime.WorkflowIdled += new EventHandler<System.Workflow.Runtime.WorkflowEventArgs>(WorkflowRuntime_WorkflowIdled);return sh;}void WorkflowRuntime_WorkflowIdled(object sender, System.Workflow.Runtime.WorkflowEventArgs e){ReadOnlyCollection<WorkflowQueueInfo> queues;queues = e.WorkflowInstance.GetWorkflowQueueData();foreach (WorkflowQueueInfo qi in queues){Debug.WriteLine("QueueName : " + qi.QueueName);foreach (string actName in qi.SubscribedActivityNames){Debug.WriteLine("Activity subscribed: " + actName);}}}}
And my svc file:
<%@ ServiceHost Service="WorkflowArtifacts.AccumWorkflow"Factory="MyWorkflowServiceHostFactory" %>
WCF | WF Comments [0]
Remember Me