Strongly typed workflow input and output arguments

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:


Running workflow with strongly typed argument

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.


image

The Request parameters is of type
IUserVisitWorkflowRequest. So, you can pass any class as
Request argument that implements the interface.


image

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.


image

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:


image

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.


image

This way, I can run Workflow in strongly typed fashion:


image

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.

3 thoughts on “Strongly typed workflow input and output arguments”

  1. Thanks for this. This is really cool technique that we can use. Using validation app block, we can validate the class instance coming into WF to make sure we have all the data we need to proceed.

    Harsha
    idispensable.blogspot.com

Leave a Reply