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 (inside a ViewController descendant) will start the workflow on the server asynchronously:
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Workflow;
using DevExpress.ExpressApp.Workflow.Xpo;
using DevExpress.ExpressApp.Xpo;
namespace YourSolutionName.Module.Controllers {
public class YourControllerName : ViewController {
public void SomeMethodName() {
var criteriaOperator = CriteriaOperator.Parse("Name = 'My workflow'");
IWorkflowDefinition definition = View.ObjectSpace.FindObject<XpoWorkflowDefinition>(criteriaOperator);
if(definition != null) {
var request = new XpoStartWorkflowRequest(((XPObjectSpace)ObjectSpace).Session);
object currentUserId = SecuritySystem.CurrentUserId;
request.TargetWorkflowUniqueId = definition.GetUniqueId();
request.TargetObjectKey = currentUserId;
}
}
}
}
WorkFlowInvoker Solution
The following code (inside a ViewController descendant) will start the workflow in synch with the client:
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Workflow;
using DevExpress.ExpressApp.Workflow.Xpo;
using DevExpress.ExpressApp.Xpo;
using System.Activities;
using System.Activities.XamlIntegration;// You must add assembly references to System.Activities and System.Xaml.
using System.Collections.Generic;
using System.IO;
namespace YourSolutionName.Module.Controllers {
public class YourControllerName : ViewController {
public void SomeMethodName() {
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).

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

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.

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

Now, the final and most interesting part is to launch our workflow with a simple code like;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Workflow.Xpo;
using System;
using System.ServiceModel;
namespace YourSolutionName.Module.Controllers {
[ServiceContract]
public interface IPassOrder {
[OperationContract(IsOneWay = true)]
void PassOrder(Guid currentUserId, Guid productId);
}
public class YourControllerName : ViewController {
public void SomeMethodName() {
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
Free DevExpress Products - Get Your Copy Today
The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the
DevExpress Support Center at your convenience. We'll be happy to follow-up.