Peter Goodman bio photo

Peter Goodman

A developer living in Auckland building software using all sorts of bits and pieces I find along the way. Originally from Northern Ireland.

Twitter Google+ LinkedIn Github

This is the second post in a series about Building an Enterprise Workflow system with WF4.

In the previous post we discussed how the default workflow service design experience wasn’t really what we would want for an enterprise workflow system. We decided that the activity authoring experience we wanted was much better and we even hinted that the WorkflowServiceHostFactory would enable us to host an activity as a service. Lets look at how we can do this.

I have modified the Magic Eight Ball sample from the previous post to make it an activity rather than a xamlx workflow service file.

 CropperCapture[7]

In a normal .xamlx workflow service like the one you get with the workflow service library template, the web.config makes no mention of the .xamlx file or workflow or anything that would suggest the app will host a workflow. In fact the .xamlx is automatically mapped by the runtime with a default binding and endpoint using the simplified configuration feature of WCF 4. This means that a .xamlx file will be hosted as a service using the BasicHttpBinding at the address of the xamlx file, much like the svc file for standard WCF services.

We can however specify our own service activation in the web.config as follows:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  ...
  <system.serviceModel>
    ...
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" >
      <!-- Add the service Activations section-->
      <serviceActivations>
        <add relativeAddress="~/EightBall.svc"
             service="BasicMagicEightBall.EightBall, BasicMagicEightBall"
             factory=" EightBallLibrary.Hosting.EnterpriseServiceHostFactory, EightBallLibrary"/>
      </serviceActivations>
    </serviceHostingEnvironment>
  </system.serviceModel>
  ...
</configuration>

 

If we break the serviceActivation element down:

  • relativeAddress: The relative URI that we will use, this does not have to end with .xamlx and the file in the path does actually exist
  • service: The service to load, in our case this is the compiled xaml activity name and assembly name
  • factory: This is our custom service host factory

Notice that when we implement a custom class deriving from WorkflowServiceHostFactory that we have 2 overrides for CreateWorkflowServiceHost, one that takes a WorkflowService and one that takes an Activity. Obviously the second one is the one that is going to run in our case.

protected override WorkflowServiceHost CreateWorkflowServiceHost(WorkflowService service, Uri[] baseAddresses) {
    WorkflowServiceHost workflowServiceHost = base.CreateWorkflowServiceHost(service, baseAddresses);
    AddBehaviorsAndEndpoints(workflowServiceHost);
    return workflowServiceHost;
}

protected override WorkflowServiceHost CreateWorkflowServiceHost(System.Activities.Activity activity, Uri[] baseAddresses) {
    WorkflowServiceHost workflowServiceHost = base.CreateWorkflowServiceHost(activity, baseAddresses);
    AddBehaviorsAndEndpoints(workflowServiceHost);
    return workflowServiceHost;
}

 

We can add our own behaviors etc, hence the call to my AddBehaviorsAndEndpoints method. With this we can do many things to configure our WorkflowServiceHost including:

  • Hard Code Instance Store persistence
  • Add WF Idle Behavior
  • Add WF Unhandled Exception Behavior
  • Add a WF control endpoint for controlling running instances
  • Add a custom WF tracking behavior
  • Add custom WF extensions
  • Customize behaviors etc on WF hosted endpoints (Like adding security behaviors etc)
  • Add a WF Creation Endpoint – more on that later.

Now we have a workflow activity hosted as a service, just one problem. Remember that in our workflow service xamlx created by the Workflow Service Library project template we had a Receive activity with a SendReply. If you look closer on the properties for the Receive activity you will notice that there is a property called CanCreateInstance set to true.

When you have a Receive /SendResponse activity pair on a workflow definition, the workflow service host sets up that activity pair as a WCF service operation on the workflow service when the service host starts. If it has “CanCreateInstance” set, any call to that service operation will create a new instance of our workflow definition.

With our new hosted activity we have no way of starting a new instance as we do not have a Receive activity waiting on an incoming call. This is where the WorkflowCreationEndpoint comes in, it will allow us to have a standard contract for creating new instances of our workflow, it will also be the subject of the next post.

Download the Code EnterpriseWorkflowDemo.zip