When you run a Workflow using Workflow Foundation, you
pass arguments to the workflow in a Dictionary form where
the type of Dictionary is Dictionary
This means you miss the strong typing features of .NET languages.
You have to know what arguments the workflow expects by looking at
the Workflow public properties. Moreover, there’s no
way to make arguments required. You pass parameter, expect it to
run, if it throws exception, you pass more arguments, hope it works
now. Similarly, if you are running workflow synchronously using
ManualWorkflowSchedulerService, you expect return arguments
from the Workflow immediately, but there again, you have to rely on
the Dictionary key and value pair. No strong typing there as
well.
In order to solve this, so that you could pass Workflow
arguments as strongly typed classes, you can establish a format
that every Workflow has only two arguments named
“Request” and “Response” and none other. Whatever
needs to be passed to the Workflow and expected out of it,
must be passed via Request and must be expected via Response
properties. Now the type of these arguments can be workflow
specific, it can be any class with one or more parameters. This
way, you could write code like this:
The advantages of these strongly typed approach are:
- Compile time validation of input parameters passed to workflow.
No risk of passing unexpected object in Dictionary’s
object type value. - Enforce required values by creating Request objects with
non-default constructor. - Establish a fixed contract for Workflow input and output via
the strongly typed Request and Response classes or interfaces. - Validate input arguments for the Workflow directly from the
Request class, without going through the overhead of running a
workflow.
If we follow this approach, we create workflows with only two
DependencyProperty, one for Request and one for
Response. Showing you an example from my open source project
Dropthings, which uses Workflow for the entire
Business Layer. Below you see the Workflow that executes when a new
user visits Dropthings.com, creates a new user and setups all the
pages and widgets for the user. It has only two Dependency
property – Request and Response.
The Request parameters is of type
IUserVisitWorkflowRequest. So, you can pass any class as
Request argument that implements the interface.
Here I have used fancy inheritance to create Request object
hierarchy. You don’t need to do that. Just remember, you can
pass any class. You don’t even need to use interface for
Request parameter. It can be a class directly. I use all these
interfaces in order to facilitate Dependency Inversion.
Similarly, the Response object is also a class.
The Response returns quite some properties. So, it’s kinda
handy to wrap them all in one property.
So, there you have it, strongly typed Workflow arguments. You
can attach properties of the Request object to any activity
directly form the designer:
There’s really no compromise to make in this approach.
Everything works as before.
In order to make workflow execution simpler, I use a helper
method like the following, that takes the Request and Response
object and creates the Dictionary for me. This Dictionary always
contains one “Request” and one “Response”
entry.
This way, I can run Workflow in strongly typed fashion:
Here I can specify the Request, Response and Workflow type using
strong typing. This way I get strongly typed return object as well
as pass strongly type Request object. There’s no dictionary
building, no risky string key and object type value passing.
You can ignore the ObjectContainer.Resolve() stuff, because
that’s just returning me an existing reference of
WorkflowRuntime.
Hope you like this approach.