Jun 23, 2009

ActivityExecutionContext

  1. It is a container of services that is availabe to activities ruing their execution. This set of service is the same for all activities in all WF program instances. Some services are provided by the WF runtime and are always obtainable from AEC. Custom services can be offered by the application that hosts the WF runtime; such services are made available to activities by using the AddService method of WorkflowRuntime.
    class ReadLine:Activity
    {
        private string text;
        public string Text
        {
            get { return text; }
        }
    
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            WorkflowQueuingService qService = executionContext.GetService();
            WorkflowQueue queue = qService.CreateWorkflowQueue(this.Name, true);
            queue.QueueItemAvailable += ContinueAt;
            return ActivityExecutionStatus.Executing;
        }
    
        void ContinueAt(object sender, QueueEventArgs e)
        {
            ActivityExecutionContext context = sender as ActivityExecutionContext;
            WorkflowQueuingService qService = context.GetService();
            WorkflowQueue queue = qService.GetWorkflowQueue(this.Name);
            text = (string)queue.Dequeue();
            qService.DeleteWorkflowQueue(this.Name);
            context.CloseActivity();
        }
    }
    
    
    
  2. ActivityExecutionContext is as an API surface through which activities can interact with the (internal) scheduler component of the WF runtime. For example, the ExecuteActivity method requests that a work queue. The CloseActivity method requests that the WF runtime finalize the current activity's transition to the Closed state, and resume the internal bookmark that notifies the parent composite activity of the activity's completion. AEC therefore abstracts the internal machinery of the WF runtime; even though we have explained the execution model of the WF runtime in terms of a scheduler and a work queue, these entities are not represented directly in the public API of the WF programming model.
    public class Sequence : CompositeActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
        {
            if (this.EnabledActivities.Count == 0)
                return ActivityExecutionStatus.Closed;
    
            Activity child = this.EnabledActivities[0];
            child.Closed += this.ContinueAt;
            context.ExecuteActivity(child);
    
            return ActivityExecutionStatus.Executing;
        }
    
        void ContinueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
        {
            ActivityExecutionContext context = sender as ActivityExecutionContext;
            e.Activity.Closed -= this.ContinueAt;
            int index = this.EnabledActivities.IndexOf(e.Activity);
    
            if ((index + 1) == this.EnabledActivities.Count)
            {
                context.CloseActivity();
            }
            else
            {
                Activity child = this.EnabledActivities[index + 1];
                child.Closed += this.ContinueAt;
                context.ExecuteActivity(child);
            }
        }
    }
    
    
    
  3. The execution of a WF program instance is episodic, and at the end of each episode when the WF program instance becomes idle, the instance can be persisted in durable storage as continuation. This continuation, because it represents the entirety of the program instance's state that is necessary for resuming its execution, holds the relevant (internal) WF runtime execution state plus user-defined state, sometimes called the application state. The application state is nothing but the WF program instance's tree of activities (the actual CLR objects), which are usually stateful entities. The runtime state includes the state of the scheduler work queue, WF program queues, and bookkeeping information about internally managed bookmarks (such as subscriptions to the Activity.Closed event).

    The resumption point of a bookmark is called an execution handler, so we can refer to the (heap-allocated) execution state required by an execution handler as its execution context. Because an execution handler is typically a method on an activity, we will often refer to this execution context as activity execution context.

    ActivityExecutionContext is a programmatic abstraction for precisely this execution context. ActivityExecutionContext is passed to every execution handler either as an explicit argument (as for Activity.Execute) or as the sender parameter in the case of execution handlers that conform to a standard .NET Framework event handler delegate type.