-
Notifications
You must be signed in to change notification settings - Fork 11
Introduction
Windows Workflow Foundation 4 offers a comprehensive set of tools to design, create and host your own workflows in your application. Normally when working with WF4 the only way to get your external dependencies into the workflow is by passing the dependencies as arguments to the workflow host such as WorkflowApplication, _WorkflowInvoker _or WorkflowServiceHost.
This might look like the following code illustrated (using ninject):
public sealed class Divide : CodeActivity
{
[RequiredArgument]
public InArgument<int> Dividend { get; set; }
[RequiredArgument]
public InArgument<int> Divisor { get; set; }
[RequiredArgument]
public InArgument<ICalculator> Calculator { get; set; }
public OutArgument<int> Remainder { get; set; }
public OutArgument<int> Result { get; set; }
protected override void Execute(CodeActivityContext context)
{
var calculator = this.Calculator.Get(context);
int quotient = calculator.Divide(Dividend.Get(context),Divisor.Get(context));
int remainder = calculator.Reminder(Dividend.Get(context), Divisor.Get(context));
Result.Set(context, quotient);
Remainder.Set(context, remainder);
}
}
var calculator = this.Kernel.Get<ICalculator>();
int dividend = 500;
int divisor = 36;
var inputs = new Dictionary<string, object>();
inputs.Add("Dividend", dividend);
inputs.Add("Divisor", divisor);
inputs.Add("Calculator", calculator);
WorkflowApplication wfApp = new WorkflowApplication(new Divide(), inputs);
wfApp.Run();
The same would be true for workflows executed in the WorkflowInvoker. For complex workflows this can become really messy and the dependencies would clutter the actual code which passes the workflow related input data into the host. But what if you would like to test drive your own activities in code and then build your whole workflow using code first or designer first approach? I will come to that later, keep this thought in mind!
To get a bit deeper into the problematic of DI with Windows Workflow Foundation 4 we must quickly look into the differences between the _WorkflowApplication _and the WorkflowInvoker:
Using _WorkflowApplication _you can perform the following tasks
- Create a new workflow instance, or load a workflow instance from an instance store.
- Provide extensions to be used by activities within a workflow instance.
- Control the execution of a workflow instance.
- Resume a bookmark created by an activity within a workflow instance.
- Persist or unload a workflow instance.
- Be notified of workflow instance lifecycle events.
and the WorkflowInvoker:
WorkflowInvoker contains both instance and static methods for invoking workflows synchronously, and instance methods for invoking workflows asynchronously. WorkflowInvoker does not allow instance control such as persisting, unloading, or resuming bookmarks. If instance control is desired, use WorkflowApplication instead.
Both the WorkflowApplication and the WorkflowInvoker offer an WorkflowExtensionManager which allows to register extensions which can be used by activities within a workflow instance. Extensions can for example be used to wait for a certain event and on a certain event resume the bookmark of an idle workflow. Normally the pattern of defining and adding extensions looks like the following:
// when inheriting from NativeActivity
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
// Tell the runtime that we need this extension
metadata.RequireExtension(typeof (SomeExtension));
// Provide a Func<T> to create the extension if it does not already exist
metadata.AddDefaultExtensionProvider(() => new SomeExtension());
}
protected override void Execute(NativeActivityContext context)
{
// Get (which may create) the extension
var extension = context.GetExtension<SomeExtension>();
// do something on the extension
extension.Do(/*whatever*/);
}
// or directly on Invoker or Application.
WorkflowApplication wfApp = new WorkflowApplication(new Divide(), inputs);
wfApp.Extensions.Add(new SomeExtension()); /* Registered as singleton */
wfApp.Extensions.Add(() => new SomeExtension()); /* Registered as transient */
wfApp.Run();