Manually starting workflows

XAF Team Blog
19 July 2011

In this post we are going to explore 2 different ways to start a workflow. So far we have looked at using the workflow server, together with the ObjectCreated and ObjectFitsCriteria, to automatically start the workflow. However there is often a necessity to start workflows from a client whilst entering additional parameters.

Scenario 1

An order form has been completed and the user hits enter. This will initiate a workflow that will asynchronously notify a call center employee to contact that user.

XpoStartWorkflowRequest Solution

The below code will start the workflow on the server asynchronously

var criteriaOperator = CriteriaOperator.Parse("Name = 'My workflow'");

IWorkflowDefinition definition = View.ObjectSpace.FindObject<XpoWorkflowDefinition>(criteriaOperator);

if (definition != null) {

    var request = new XpoStartWorkflowRequest(((ObjectSpace)ObjectSpace).Session);

    object currentUserId = SecuritySystem.CurrentUserId;

    request.TargetWorkflowUniqueId = definition.GetUniqueId();

    request.TargetObjectKey = currentUserId;

}

 

WorkFlowInvoker Solution

The following code will start the workflow in synch with the client

 

var criteriaOperator = CriteriaOperator.Parse("Name = 'My workflow'");

IWorkflowDefinition definition = View.ObjectSpace.FindObject<XpoWorkflowDefinition>(criteriaOperator);

if (definition != null) {

    Activity activity = ActivityXamlServices.Load(new StringReader(definition.Xaml));

    var args = new Dictionary<string, object> {{"targetObjectId", SecuritySystem.CurrentUserId}};

    WorkflowInvoker invoker = new WorkflowInvoker(activity);

    invoker.Extensions.Add(Application.ObjectSpaceProvider); // You may want to modify this line to obtain a valid provider from a different place or even create it from scratch.

    IDictionary<string, object> results = invoker.Invoke(args);

    // If needed

    //((MyObject)View.CurrentObject).WorkflowResultData = (int)results["SomeIntOutArgument"];

}

 

Scenario 2

Let’s make Scenario 1 a little bit more interesting by providing the option to choose a Product when placing the order. This time together with the current user id we need to set an additional parameter - the product id.

WCF Solution

It is interesting to note that it is also possible to apply the WorkFlowInvoker Solution from Scenario 1 here. This is because the WorkflowInvoker can receive a range of arguments. Now, in order to to model our workflow we are going to use the runtime designer. We need to create a new workflow definition, name it and set its target object to a dummy value. Since we are going to invoke the workflow using a WCF service the target object is redundant, however it is mandatory. The same rule applies to the other start workflow conditions (AutoStartWhenObjectIsCreated, AutoStartWhenObjectFitsCriteria).

image

Next we are going to use the native receive activity and bind it to the WCF service as shown.

image

it is imperative to check the CanCreateInstance attribute at this stage. At the same time we need to set the OperationName and ServiceContactName and define the following contract;

[ServiceContract]

public interface IPassOrder {

    [OperationContract(IsOneWay = true)]

    void PassOrder(Guid currentUserId, Guid productId);

}

 

Two variable declarations (productId, currentUserId) are required in order to hold them for later use. Moreover we need to assign them from the OperationName arguments.

 

 

image

To finish designing we can create a Task that will inform the employee. You can read more on this here.

image

Now, the final and most interesting part is to launch our workflow with a simple code like;

var criteriaOperator = CriteriaOperator.Parse("Name=?", "Contact customer");

var workflowDefinition = ObjectSpace.FindObject<XpoWorkflowDefinition>(criteriaOperator);

var uri = "http://localhost:46232/" + workflowDefinition.GetUniqueId();

var newEndpointAddress = new EndpointAddress(uri);

var serverWorkflow = ChannelFactory<IPassOrder>.CreateChannel(new BasicHttpBinding(), newEndpointAddress);

var productId = Guid.NewGuid();

serverWorkflow.PassOrder((Guid)SecuritySystem.CurrentUserId, productId);

 

 

 

We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us  with any further questions

Related Links
Online documentation
Blog posts

7 comment(s)
Robert Fuchs
Robert Fuchs

Great post, thanks.

Robert

18 July, 2011
Robert Fuchs
Robert Fuchs

Tolis,

I would like to see an example about how to start workflows via eXpand Quartz. Would this be possible?

Thanks in advance.

18 July, 2011
Simon de Kraa
Simon de Kraa

Thanks Tolis! :-)

19 July, 2011
Apostolis Bekiaris (DevExpress)
Apostolis Bekiaris (DevExpress)

Thanks for your comments guys!

@Robert in this post apobekiaris.blogspot.com/.../xaf-quartz-jobscheduler-module.html you can see that IXpandScheduler exposes a XafApplication instance. This means that you can use it

to start your workflows as described here. eXpandFramework, in the future is going to use Quartz triggering logic to create activities that can be schedule.

19 July, 2011
Robert Fuchs
Robert Fuchs

@Tolis: Ican see that it exposes a XafApplication instance - but I don't know how to do it. That's why I asked for an example.

> eXpandFramework, in the future is going to use Quartz

> triggering logic to create activities that can be schedule

Hmm, and that means? ...

19 July, 2011
Maxim Guz
Maxim Guz

Very useful, thanks.

I would like to see an example about how to design workflow with send activity.

16 November, 2011
Warren Connors 4
Warren Connors 4

Great post, Tolis!

25 February, 2015

Please login or register to post comments.