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<string, object>. 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.