Workflow and Host Communication in WF 4.0–Bookmarks

Posted: April 22, 2012 in .NET, C#, WF
Tags: ,

In the last post we have discussed at length about different mechanisms of parameter passing and obtaining results from a workflow.In this post we will discuss about another extremely important aspect of workflow and host communication i.e. Bookmarks. Bookmarks as the name suggests is a like Bookmark for a book. When created at a particular point in the execution of the workflow , the execution is suspended and the workflow waits to be resumed.When a bookmark is resumed it starts executing exactly from the same point.

To create a Bookmark we need to define a custom native activity deriving from System.Activities.NativeActivity class. The Execute method of this custom activity accepts a System.Activities.NativeActivityContext object as parameter.NativeActivityContext provides a method called CreateBookmark which is used to create the bookmark. One of the commonly used overloads of this method is:

  
public Bookmark CreateBookmark(string name, BookmarkCallback callback);

BookmarkCallback is a delegate to provide a callback method.This is invoked when the Bookmark is resumed. The signature of this delegate is:

  
public delegate void BookmarkCallback(NativeActivityContext context, Bookmark bookmark, object value);

The last parameter “value” contains the value of any input that is passed by the host to the workflow while resuming the bookmark.

The below shows a custom activity which creates a bookmark,in the bookmark callback expects an array of integer which is set to 2 output arguments of the activity.

  
public class GetInput:NativeActivity 
    { 
        public OutArgument<Int32> Number1 { get; set; } 
        public OutArgument<Int32> Number2 { get; set; } 
        protected override void Execute(NativeActivityContext context) 
        { 
            context.CreateBookmark("WaitForInput",(c, b, o) => 
            { 
                var nums = o as Int32[]; 
                if (o != null) 
                { 
                    Number1.Set(c, nums[0]); 
                    Number2.Set(c, nums[1]); 
                } 
            });

        } 
        protected override bool CanInduceIdle 
        { 
            get 
            { 
                return true; 
            } 
        } 
    }

The property CanInduceIdle indicates whether this activity puts the workflow in Idle state or not. This activity creates a bookmark and when a bookmark is created workflow goes into idle state so this is set to true.

We will use this activity in a simple sequential workflow which accepts to numbers from the command prompt, adds them and returns the result as output.

bookmark1

There are two workflow variables defined i and j.

bookmark2

These two are assigned to the out arguments of the “GetInput” activity.

bookmark3

Using the built-in Assign activity the sum of  i and j is set to the out argument of the workflow i.e. “Result”.

image

We have to now execute the workflow.Here, we have to use WorkflowApplication as WorkflowInvoker does not support bookmarks.

  
class Program 
    { 
        static void Main(string[] args) 
        { 
            var flag = new AutoResetEvent(false); 
            var app = new WorkflowApplication(new MyCalculatorWorkflow()); 
            app.Idle = (e)=>{

                Console.WriteLine("Workflow is Idle.."); 
                flag.Set(); 
            }; 
            app.Completed = (e) => 
            { 
                Console.WriteLine("Workflow Completed.."); 
                if (e.Outputs["Result"] != null) Console.WriteLine("Result is {0}", 
                    e.Outputs["Result"].ToString()); 
                flag.Set();

            }; 
            app.Run(); 
            flag.WaitOne(); 
            Console.WriteLine("Please enter number 1"); 
            var input = Console.ReadLine(); 
            var i = Convert.ToInt32(input); 
            Console.WriteLine("Please enter number 2"); 
            input = Console.ReadLine(); 
            var j = Convert.ToInt32(input); 
            flag.Reset(); 
            app.ResumeBookmark("WaitForInput", new Int32[] { i, j }); 
            flag.WaitOne();

            Console.ReadLine(); 
        }

The above program does the following:

  • Instantiates a WorkflowApplication
  • The Completed and Idle event handlers are provided to track when the workflow is going idle and to get the back the output from the workflow respectively.
  • The workflow is started in asynchronous mode (as the Run method is async by default) and the main execution thread waits on the AutoResetEvent object.
    • The “GetInput” activity is executed.
    • A bookmark is created and workflow moves into Idle state
    • The Idle event handler is executed which signals the AutoResetEvent object.
  • The main thread of execution proceeds again.
  • Captures two number input from the console.
  • Invokes the ResumeBookmark method and passes the integer values
    • BookmarkCallback is executed and it assigns the integers passed from console to the two out arguments of the “GetInputs” activity.
  • The workflow is completed and completed event handler executes and prints the output of the workflow to the console.

The output of the program is shown below:

bookmark4

About these ads
Comments
  1. Dotnet Techy says:

    Great Article :)

    We can also submit our .net related links on http://www.dotnettechy.com to improve traffic.

    The dotnettechy.com is a community of .Net developers joined together to learn, to teach, to find solutions, to find interview questions and answers, to find .net website / blog collection and to have fun programming.

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