A question recently came up on an internal list about how to start a workflow to do some work and then have it accept a message via a Receive activity. This led to an interesting discussion that provides some insight into how the WorkflowServiceHost instantiates workflows in conjunction with the ContextChannel.
By default, the WorkflowServiceHost will create a workflow when the following two conditions are true:
It is interesting to note that you don't even need to use a binding element collection that contains a ContextBindingElement. The ContextBindingElement is responsible for creating the ContextChannel. The job of the ContextChannel is to do two things on the Receive side
So, if we want to create workflows based on messages dropped into an MSMQ queue, we can do that by not trying to add the ContextBindingElement into a custom binding on top of the netMsmqBinding, and associating the operation with a Receive activity with the CanCreateInstance equaling true. Note, that any subsequent communication with the workflow will have to occur with a communication channel over which we can pass context.
In the case that this post is about, we do not want to activate off an inbound message. The way to do this doesn't require much additional work. We first need to make sure we don't have any of our Receive activities marked with CanCreateInstance to true. This means that no message coming in can activate the workflow. Our workflow will then do some work prior to executing the Receive activity and waiting for the next message. Our workflow will look like this (pretty simple)
When we want to start a workflow, we need to reach into the workflow service host and extract the workflow runtime and initiate the workflow:
WorkflowServiceHost myWorkflowServiceHost = new WorkflowServiceHost(typeof(Workflow1), null); // do some work to set up workflow service host myWorkflowServiceHost.Open(); // on some reason to start the workflow WorkflowRuntime wr = myWorkflowServiceHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime; WorkflowInstance wi = wr.CreateWorkflow(typeof(Workflow1)); wi.Start(); // need to send wi.InstanceId somewhere for others to communicate with it