Dashboard > Castle Contrib > Home > Castle.Facilities.WorkflowIntegration
Log In   View a printable version of the current page.
Castle.Facilities.WorkflowIntegration
Added by Louis DeJardin, last edited by Louis DeJardin on Apr 10, 2008  (view change) show comment
Labels: 
(None)


The Castle.Facilities.WorkflowIntegration offers simple integration and configuration of the Workflow Foundation infrastructure provided by the System.Workflow assemblies.

The primary goal is to eliminate or simplify the code needed to make a WorkflowRuntime instance available to an application.

Current Features

  • Instantiates and initializes an instance of the WorkflowRuntime. The instance is registered with the microkernel to allow components easy access to it's functionality via dependency injection.
  • Instantiates and attaches any components added to the microkernel which are descended from WorkflowRuntimeService. Constructor parameters and public properties may be configured as usual. This applies to WF runtime services like SqlWorkflowPersistenceService as well as services implemented in application code.
  • Instantiates and attaches any components which implement interfaces which have the [ExternalDataExchange] attribute.

Installation

Binaries built with Castle Project rc3 and a demo site can be downloaded from WorkflowIntegration.zip.

To install from source

The binary for the facility will be placed into the build\net-2.0 folder. The binaries for all of the projects, including unit tests and a demo site, will be placed into the bin\debug folder.

Note: This assumes the vs2005 project files will be used and the desired version of the Castle binaries are available to msbuild.

Usage

A sample project based on this page can be downloaded from WidgetSample.zip.

Configuration in Castle Windsor

<castle>
  <facilities>
    <facility id="workflow.facility"
              type="Castle.Facilities.WorkflowIntegration.WorkflowFacility, Castle.Facilities.WorkflowIntegration" />
  </facilities>
</castle>

Making and running a workflow

Assuming you have an existing solution, you'll probably want to make a new "Empty Workflow Project" assembly. Depending on what type of information you'll be working with you may not need to add any references from this project to castle assemblies. Any type of workflows and activities can be created at this point. I prefer to use the xoml based flavor (with code separation).

<SequentialWorkflowActivity x:Class="Demo.Workflows.SampleProcessing" x:Name="SampleProcessing"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
	<DelayActivity TimeoutDuration="00:00:03" x:Name="delayActivity1" />
</SequentialWorkflowActivity>

At that point you can add a reference to your workflow assembly from your project, and add references
to:

  • System.Workflow.Activities
  • System.Workflow.ComponentModel
  • System.Workflow.Runtime

Add the following proptrty to a controller or to the base controller. A constructor argument works as well.

private WorkflowRuntime runtime;

public WorkflowRuntime Runtime
{
    get { return runtime; }
    set { runtime = value; }
}

And you can use the runtime to create and start instances of the workflow.

public void SubmitSample()
{
    WorkflowInstance workflow = runtime.CreateWorkflow(typeof(SampleProcessing));
    workflow.Start();
}

You can also provide an arguments dictionary in the call to createworkflow. This can be used to assign initial values to any of the the properties in the workflow.

Calling components from a workflow 

A lot of the things a workflow will be doing will involve acquiring and manipulating things which come from the type of services and data access components which have been added to the Windsor container. Because the workflow itself is created and runs in a very controlled fashion it's impractical to use normal dependency injection. Instead you will use the support for external data exchange.

First you'll define an interface and the serializable model. The workflow assembly is an excellent place to have these.

[ExternalDataExchange]
public interface IWidgetDao
{
    Widget[] FindWidgets(string keyword);
}

[Serializable]
public class Widget
{
    private string name;
    private string description;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public string Description
    {
        get { return description; }
        set { description = value; }
    }
}

You can now use the CallExternalMethod activity in your workflow to invoke FindWidgets. This was done in the designer where it was simple to set the properties of the activity and bind the argument and return values to properties on the workflow named Keyword and Widgets.

<SequentialWorkflowActivity x:Class="Demo.Workflows.SampleProcessing" x:Name="SampleProcessing"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
	<DelayActivity TimeoutDuration="00:00:03" x:Name="delayActivity1" />
	<CallExternalMethodActivity x:Name="callExternalMethodActivity1"
                              InterfaceType="{x:Type Demo.Workflows.IWidgetDao}"
                              MethodName="FindWidgets">
		<CallExternalMethodActivity.ParameterBindings>
			<WorkflowParameterBinding ParameterName="keyword">
				<WorkflowParameterBinding.Value>
					<ActivityBind Name="SampleProcessing" Path="Keyword" />
				</WorkflowParameterBinding.Value>
			</WorkflowParameterBinding>
			<WorkflowParameterBinding ParameterName="(ReturnValue)">
				<WorkflowParameterBinding.Value>
					<ActivityBind Name="SampleProcessing" Path="Widgets" />
				</WorkflowParameterBinding.Value>
			</WorkflowParameterBinding>
		</CallExternalMethodActivity.ParameterBindings>
	</CallExternalMethodActivity>
</SequentialWorkflowActivity>

At that point you can implement the interface on a normal component in Windsor and the workflow facility will ensure that an instance of the component is made available to the workflow runtime to send calls onto. The design of the workflow runtime will take this instance and keep it for the life of the application so they should be implemented with the singleton lifestyle in mind.

Configuring workflow runtime services

The workflow runtime has a set of services it uses to perform various tasks. You can introduce any of the system services or your own services to the workflow runtime by adding them as components to your Windsor contrainer. Public properties and constructor arguments can be provided as parameters as well.

For example you could use the following to have the sql tracking service provided with workflow foundation record the execution events into your normal database. This is assuming you have a connectionString defined in the <properties> of your castle configuration, and that you have run the scripts to create the schema and procedures needed.

<component id="sqltracking.service" type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
  <parameters>
    <ConnectionString>#{connectionString}</ConnectionString>
    <IsTransactional>false</IsTransactional>
    <UseDefaultProfile>true</UseDefaultProfile>
  </parameters>
</component>

Site running on a free Atlassian Confluence Community License granted to Castle Project. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.4 Build:#809 Jun 12, 2007) - Bug/feature request - Contact Administrators