Hi,
I gone through the labs, examples etc for WWF and whilst they all demonstrate different aspects of WWF, they are all rather simplistic, implementing only a single workflow.
What happens where there is more than one For example, in ASP.NET there can only be one instance of the workflow engine per app domain. On page1.aspx, I need to execute some workflow and take action based on the result so I add an event handler, eg:
workflowRuntime.WorkflowCompleted +=
new EventHandler<WorkflowCompletedEventArgs>(WorkflowRuntime_Workflow1Completed);Another page, page2.aspx also executes workflow, so again it seems I have to hook into the WorkflowCompleted event of the engine:
workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(WorkflowRuntime_Workflow2Completed);
Is this the "correct" way to work What happens if workflow1 is still executing and workflow2 starts Will each fire the event that was attached originally (WorkflowRuntime_Workflow1Completed and WorkflowRuntime_Workflow2Completed respectively), or will the "last one in" be executed
Should the workflow itself have a completed event, or indeed should I be using some other mechanism for communicating with the host
many thanks in advance for your help guys!

Multiple workflow/more complex examples.
Andy Anderson
Hi Tomas,
I'm still not seeing how it helps (maybe it's just me).
I have a long running workflow, type A, and I attach to the workflow complete event because I want to carry out some processing when A is finished.
I then start a workflow, type B and I attach to the workflow complete event because I also want to carry out some processing once this completes.
This means I have either attached two event handlers (one for type A workflow, one for type B), or I have replaced the A handler with the B handler.
If A finishes whilst B is still executing, then this means in the first case that both completed events fire or, in the second case that the B handler fires because I have removed the A handler.
If I only have one handler for all workflow complete events across the entire application, then this would need some mechanism to differentiate between each workflow type (because the actions following A are different to the actions following B's completion), likley some big messy case statement.
Maybe I'm just missing something....
KathyA
- You have a single OnWorkflowCompleted event handler for the application.
- When you start a new workflow, you provide a new event handler tied to a specific object instance you control (such as an instance method of your Page class) to get notification when that specific workflow instance completes.
- At the same time, you build a dictionary that maps the new workflow instance ID (guid) to your new event handler you provided during workflow creation
- When the global OnWorkflowCompleted handler is called, it looks up the real event handler in the dictionary, mapping the InstanceId of the completed workflow to the event handler associated with the one of the object interested in it, and calls it.
As you can see here, the workflow type is irrelevant, because you're basically mapping a single workflow instance *to a specific object instance* (the object instance on which the method referenced by the delegate is associated with). Thus, no extra mapping is needed.Am I any clearer here
mpaleari
Actually, I wouldn't bother about the performance too much (it really isn't so much of a choke point as you might think, since it only does a very simple hash-based lookup).
That said, if, you need to support long-running workflows and survive restarts, you are right it won't work (in fact you wouldn't even be able to, since it depends on object identity).
In that case, I'm afraid that no mapping would really help you. Instead, likely you'd need to use tracking (either the built in, or an added tracking into a separate database) and just query/poll the tracking information as needed.
Dev Dan
Hi Tomas,
Yes that is clearer what you meant - though for a large application, I don't think I would want everything routed through a single point - this "global" workflow completed event - there could be hundreds of workflows!
Also, I would need to persist this dictionary incase the web app was restarted, which would liekly impact performance if a persisted dictionary is updated every time a workflow starts/stops - we will have thousands of users, over 100 pages, likely with workflows on each.
Perhaps hooking into the completed event is not the way to go, and I need to look at something else.
thanks for your suggestions
Segundo Leon
Here's a simple example of an intermediary (notice it really doesn't support long running workflows, but it should be enough for simple purposes):
public class WorkflowExecutor
{
private Dictionary<Guid, EventHandler<WorkflowCompletedEventArgs>> _map;
private WorkflowRuntime _runtime;
public WorkflowExecutor(WorkflowRuntime runtime)
{
if ( runtime == null )
throw new ArgumentNullException("runtime");
_map = new Dictionary<Guid, EventHandler<WorkflowCompletedEventArgs>>();
_runtime = runtime;
_runtime.WorkflowCompleted += OnWorkflowCompleted;
}
public WorkflowInstance StartWorkflow(Type workflowType,
EventHandler<WorkflowCompletedEventArgs> eventHandler)
{
if ( workflowType == null )
throw new ArgumentNullException("workflowType");
if ( eventHandler == null )
throw new ArgumentNullException("eventHandler");
WorkflowInstance instance = _runtime.CreateWorkflow(workflowType);
_map.Add(instance.InstanceId, eventHandler);
instance.Start();
return instance;
}
private void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs args)
{
EventHandler<WorkflowCompletedEventArgs> eventHandler =
_map[args.WorkflowInstance.InstanceId];
eventHandler(_runtime, args);
}
}
// create the one and only WorkflowRuntime and WorkflowExecutor instances
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
WorkflowExecutor workflowExecutor = new WorkflowExecutor(workflowRuntime);
// start a workflow instance:
WorkflowInstance instance = workflowExecutor.StartWorkflow(
typeof(CustomDesignerShapeDemo.Workflow1),
p.OnMyWorkflowCompleted
);
This way you could assume that you registered an instance method of your page class (or whatever is tied to your specific workflow instance) and have it called only when *that* specific workflow instance completes, but not when others do.
Jeroen Landheer
I had a similar issue which has been resolved.
http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=309564&SiteID=1
Hope this helps.
WimV
Hi Tomas,
Thanks for the response and the code sample.
My concern with having to hook into the completed event of the workflow runtime (rather than some completed event of an instance of a workflow) is that I might have two workflows running at the same time, both with completed event handlers - it seems that potentially then the runtime will fire BOTH events when one workflow completes, or regardless of which one has just completed, it will be last event handler that was attached that gets called.
Having one handler for all workflows and them some massive case statement to take action depending on which workflow has completed would not be great either.
Is there some other way to determine a workflow has completed
What are people doing in "real" apps with multiple workflows
Stephen Walters
Hi,
Interesting, but not quite the same issue - though I'm sure I would have gotten to that eventually too!
Your problem was differentiating between different instances of the same workflow, whereas mine is dealing with different types of workflow. Since you can only have one workflow engine per app domain, that means one for the entire asp.net site we are doing - which will have different workflows on different pages, and I need to get for example a yes/no answer regarding a decision, or I need to pass in a customer id and have it return an object graph or a table of customer orders etc...
Chris Bower