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.
Image may be NSFW.
Clik here to view.
There are two workflow variables defined i and j.
Image may be NSFW.
Clik here to view.
These two are assigned to the out arguments of the “GetInput” activity.
Image may be NSFW.
Clik here to view.
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 may be NSFW.
Clik here to view.
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:
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
Clik here to view.
