Thursday, May 29, 2008

Workflow Runtime Manager - Streamlined Launching

If you've read Bruce Bukavics's "Pro WF - Windows Workflow in .NET 3.0", you may have seen some code for a Workflow Runtime Manager that wraps common steps to managing your Workflow Runtime such as launching workflows, adding services, retrieving output parameters and capturing exceptions from a workflow instance.

I expanded upon Bruce's implementation in two simple yet useful ways.  First, I created an interface from it.  I know, that's revolutionary! and nobody else would have ever though of that!  *cough*  *cough*  Anyway, that's not the point of this post.  I just needed to state that because I'm about to show you a clipping of the interface derived from Bruce's implementation.

public interface IWorkflowRuntimeManager
{
	...
	WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary<string, object> parameters);
	...
}

The problem with this is that I still have to set up that dictionary of parameters.  And what if I want to launch this workflow from multiple locations in my code?  I have to reinvent the wheel each time.  And how do I ensure that everyone is supplying the correct set of input parameters and they're named the same?  That's easy!  With the addition of another interface.

using System;
using System.Collections.Generic;

namespace Ipc.Framework.Workflow.Hosting
{
	/// <summary>
	///		Provides an interface for starting a workflow using
	///		<see cref="IWorkflowRuntimeManager"/>
	/// </summary>
	public interface IWorkflowStartInfo
	{
		/// <summary>
		///		The type of workflow that the <see cref="IWorkflowRuntimeManager"/>
		///		implementation should create and launch.
		/// </summary>
		Type WorkflowType { get; }

		/// <summary>
		///		The dictionary of parameters to feed to the new workflow instance.
		/// </summary>
		Dictionary<string, object> Parameters { get; }
	}
}

This interface basically describes how to build a key to start the car.  I simply write a class that implements this interface for each workflow defined in my project.  See an example implementation below.

public class HelpDeskCaseWorkflowStartInfo : IWorkflowStartInfo
{
	private const string PARAM_CASEID = "CaseId";

	private readonly Dictionary<string, object> _parameters;

	public HelpDeskCaseWorkflowStartInfo(int caseId)
	{
		_parameters = new Dictionary<string, object>();

		_parameters.Add(PARAM_CASEID, caseId);
	}

	#region IWorkflowStartInfo Members

	public Type WorkflowType
	{
		get { return typeof (HelpDeskCaseWorkflow); }
	}

	public Dictionary<string, object> Parameters
	{
		get { return _parameters; }
	}

	#endregion
}

And for the final step, let's expand the IWorkflowRuntimeManager interface as shown below.  The two functions accomplish the same task, but the second method allows compile-time binding of parameters wherever it is used (you just have to do the work to make sure that the parameter names you use in the implementation are correct).

public interface IWorkflowRuntimeManager
{
	...
	WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary<string, object> parameters);

	WorkflowInstanceWrapper StartWorkflow(IWorkflowStartInfo startInfo);
	...
}

Submit this story to DotNetKicks

0 comments: