Workflow and Host Communication in WF 4.0–Parameter Passing

Posted: April 8, 2012 in .NET, WF
Tags: , ,

Workflow host is an application responsible for executing the workflow and managing different workflow lifecycle events like start, completion, idle, unloaded etc.Now the workflow host should be capable of exchanging information with the workflow. This information exchange can be broadly categorized into:

a) The parameters/arguments needed to start the workflow and to get the results back after workflow has executed.

b) The intermediate data needs at different stages of a long running workflow (e.g. when the workflow is waiting for a specific input like Manager’s Approval).

In this post we will concentrate on the different mechanisms of parameter passing and getting results back. In the subsequent posts we will move into more complex scenarios related to long running workflows.

WF 4.0 provides two classes for hosting and managing the workflows System.Activities.WorkflowInvoker and System.Activities.WorkflowApplication.WorkflowInvoker provides a simple model to execute the workflow like a method call whereas WorkflowApplication much greater flexibility to execute and manage the workflow instance. To start with we will explore the different mechanisms to pass data back and forth using WorkflowInvoker and WorkflowApplication.

I am using a simple Add workflow for these samples which takes two integers as input and returns an integer by adding the two inputs.

addwf

a)WorkflowInvoker

i) Using the static method Invoke

WorkflowInvoker provides a static method called Invoke with the following signature to invoke a workflow synchronously.

public static IDictionary<string, Object> Invoke(Activity workflow,IDictionary<string, Object> inputs)

This method accepts a Dictionary of input parameters as name/value pairs mapped to the workflow input argument name and returns an Dictionary with workflow output arguments.

public static void Demo01() 
{ 
    IDictionary<string, object> param = new Dictionary<string, object>(); 
    param.Add("Number1", 10); 
    param.Add("Number2", 20);

    IDictionary<string, object> result = WorkflowInvoker.Invoke(new MyAddWorkflow(), param);

    Console.WriteLine("Result:{0}", result["Result"].ToString());

} 


Now let’s focus on another interesting overload of the Invoke method:

public static TResult Invoke<TResult>(Activity<TResult> workflow,IDictionary<string, Object> inputs)

This method takes a Activity<TResult> as input. As opposed to standard Activity class , Activity<TResult> inherits from the class ActivityWithResult and it returns a value of Type TResult. This value is stored in the Result property of this object.

To demonstrate the use of this I will use another activity/workflow as shown below:

public class MyAddWithResult : CodeActivity<int> 
    { 
        public InArgument<Int32> Number1 { get; set; } 
        public InArgument<Int32> Number2 { get; set; }

        protected override int Execute(CodeActivityContext context) 
        { 
            int i = Number1.Get(context); 
            int j = Number2.Get(context);

            return i + j; 
        } 
    }

This custom activity inherits from CodeActivity<Int32> and hence is supposed to return a value of type Int32. This return value will be mapped to the return value of Invoke method as shown below:

public static void Demo02() 
      { 
          IDictionary<string, object> param = new Dictionary<string, object>(); 
          param.Add("Number1", 10); 
          param.Add("Number2", 20);

          int result = WorkflowInvoker.Invoke<int>(new MyAddWithResult(), param);

          Console.WriteLine("Result:{0}", result); 
      } 


ii) Using the instance method InvokeAsync

The Invoke method as mentioned earlier is a synchronous blocking call.

The InvokeAsync method provides a way to make an asynchronous call to the workflow.  One of the most commonly used overloads is shown below which takes a dictionary of inputs and makes an async call.

public void InvokeAsync(IDictionary<string, Object> inputs)

The WorkflowInvoker class also provides an event InvokeCompleted which can be used to retrieve the return values from the asynchronous call using the Output property of the InvokeCompletedEventArgs  as shown below:

public static void Demo03() 
{ 
    IDictionary<string, object> param = new Dictionary<string, object>(); 
    param.Add("Number1", 10); 
    param.Add("Number2", 20);

    WorkflowInvoker wf = new WorkflowInvoker(new MyAddWorkflow()); 
    wf.InvokeCompleted += (s,e)=>{

        if(e.Error==null && !e.Cancelled) 
        { 
            Console.WriteLine(e.Outputs["Result"].ToString()); 
        } 
    };

    wf.InvokeAsync(param); 
} 

iii) Using the instance method Begin/EndInvoke

The WorkflowInvoker also support the standard .NET Asynchronous Programming Model (APM) with BeginInvoke and EndInvoke methods as shown below:

public static void Demo04()  
{ 
            IDictionary<string, object> param = new Dictionary<string, object>(); 
            param.Add("Number1", 10); 
            param.Add("Number2", 20);

            WorkflowInvoker wf = new WorkflowInvoker(new MyAddWorkflow());

            IAsyncResult ar = wf.BeginInvoke(param, 
                           (r) => 
                           { 
                               Console.WriteLine("Workflow Completed.."); 
                           }, 
                           new object()); 
            if (ar.IsCompleted) 
            { 
               IDictionary<string, object> result = wf.EndInvoke(ar); 
               Console.WriteLine("Result:{0}", result["Result"].ToString()); 
            } 
           
        }

b)WorkflowApplication

WorkflowApplication provides an instance method Run() which executes the workflow asynchronously.

The input parameters can be passed to the constructor while creating the WorkflowApplication instance and results can be retrieved from the Completed event as shown below:

public static void Demo05() 
        { 
            IDictionary<string, object> param = new Dictionary<string, object>(); 
            param.Add("Number1", 10); 
            param.Add("Number2", 20);

            WorkflowApplication wf = new WorkflowApplication(new MyAddWorkflow(),param); 
            wf.Completed = (e) => 
            { 
                if (e.CompletionState == ActivityInstanceState.Closed) 
                { 
                    Console.WriteLine(e.Outputs["Result"].ToString()); 
                } 
            }; 
            wf.Run();

        }


WorkflowApplication also supports the asynchronous programming model with Begin/EndRun methods as shown below:

public static void Demo06() 
        { 
            IDictionary<string, object> param = new Dictionary<string, object>(); 
            param.Add("Number1", 10); 
            param.Add("Number2", 20);

            WorkflowApplication wf = new WorkflowApplication(new MyAddWorkflow(), param); 
            IAsyncResult ar = wf.BeginRun( 
                           (r) => 
                           { 
                               Console.WriteLine("Workflow Completed.."); 
                           }, 
                           new object() 
                       ); 
            if (ar.IsCompleted) 
            { 
                wf.EndRun(ar); 
            } 
        }

About these ads
Comments
  1. […] the last post we have discussed at length about different mechanisms of parameter passing and obtaining results […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s