Tracking


It is generally useful, and in some scenarios critical, for the application that is hosting the WF runtime to obtain information about WF program instances as they are executing. Here we are not talking about the sending of data as modeled in the WF program; instead, what we are after are generic events that inform us of lifecycle transitions for WF program instances and the activities within them.

To this end, you can add one or more tracking services to the WF runtime, and these services will receive data, via the WF runtime, about WF program instances that are executing. There is no burden placed here upon the WF program author; the events that are tracked are generic in nature (though as we shall see there is also a notion of a custom tracking event).

All tracking services must derive from the trackingService type (shown in Listing 8.17) and implement several abstract methods. trackingService, along with the rest of the WF tracking infrastructure, is defined in the System.Workflow.Runtime.Tracking namespace.

Listing 8.17. trackingService

 namespace System.Workflow.Runtime.Tracking {   public abstract class TrackingService : WorkflowRuntimeService   {     protected abstract bool TryGetProfile(       Type workflowType, out TrackingProfile profile);     protected abstract TrackingChannel GetTrackingChannel(       TrackingParameters parameters);     /* *** other members *** */   } } 


Tracking services utilize tracking profiles to express to the WF runtime which events they care to receive. The WF runtime calls the tryGetProfile method of trackingService to obtain a tracking profile for each new WF program instance that is created. tryGetProfile returns a Boolean value that indicates whether or not tracking should occur at all for the specified instance; if the return value is true, the out parameter named profile is the tracking profile that will be used for the WF program instance.

The System.Workflow.Runtime.Tracking.TrackingProfile type is shown in Listing 8.18.

Listing 8.18. trackingProfile

 namespace System.Workflow.Runtime.Tracking {   public class TrackingProfile   {     public TrackingProfile();     public ActivityTrackPointCollection ActivityTrackPoints { get; }     public WorkflowTrackPointCollection WorkflowTrackPoints { get; }     public UserTrackPointCollection UserTrackPoints { get; }     public System.Version Version { get; set; }   } } 


A tracking channel is the conduit along which tracking events flow from the WF runtime to a tracking service. This is depicted in Figure 8.3.

Figure 8.3. A tracking service receives data from a tracking channel.


The System.Workflow.Runtime.Tracking.TrackingChannel type is shown in Listing 8.19. A tracking service must manufacture its own tracking channels; typically, a unique tracking channel object will be provided for every executing WF program instance. The System.Workflow.Runtime.Tracking.TrackingParameters type carries information that can be used to identify the WF program instance with which a tracking channel is associated.

Listing 8.19. trackingChannel

 namespace System.Workflow.Runtime.Tracking {   public abstract class TrackingChannel   {     protected abstract void Send(TrackingRecord record);     protected abstract void InstanceCompletedOrTerminated();   } } 


As you can see from the definition of trackingProfile (refer to Listing 8.17), there are three kinds of tracking points. An activity tracking point is at the granularity of a single activity. A workflow tracking point is at the level of a WF program instance. A custom tracking point represents the receipt of custom tracking data from an activity.

Activity tracking events occur when an activity makes a transition from one state of the activity automaton to another. A tracking profile can therefore specify an interest in the events corresponding to any or all of the values of the Activity-ExecutionStatus enumeration (defined in the System.Workflow.ComponentModel namespace), which was discussed in Chapter 3.

WF program tracking events occur when the WF program instance makes a lifecycle transition. The set of WF program tracking events is established by the trackingWorkflowEvent enumeration, defined in the System.Workflow.Runtime. Tracking namespace and shown in Listing 8.20.

Listing 8.20. trackingWorkflowEvent

 namespace System.Workflow.Runtime.Tracking {   public enum TrackingWorkflowEvent   {     Created,     Completed,     Idle,     Suspended,     Resumed,     Persisted,     Unloaded,     Loaded,     Exception,     Terminated,     Aborted,     Changed,     Started   } } 


Custom tracking events occur when activity execution logic calls the trackData method that is defined by the Activity type, as shown in Listing 8.21.

Listing 8.21. Activity.TrackData

 namespace System.Workflow.ComponentModel {   public class Activity : DependencyObject   {     protected void TrackData(object userData);     protected void TrackData(string userDataKey, object userData);     /* *** other members *** */   } } 


The object that is passed by the activity as a parameter to trackData is the data that is received by the tracking channel and can be any System.Object.

As part of activity and WF program tracking events, a tracking service can receive the values of activity fields and properties by utilizing derivatives of System.Workflow.Runtime.Tracking.TrackingExtract in the specification of tracking points within a tracking profile. Tracking points can also be made conditional in order to limit the volume of data that you receive on a tracking channel to be precisely that data in which you are interested.

Tracking data arrives on a tracking channel in the form of a tracking record. The System.Workflow.Runtime.Tracking.TrackingRecord base class has three derivativesActivityTrackingRecord, WorkflowTrackingRecord, and UserTrackingRecordthat correspond to the three previously discussed kinds of tracking points (activity level, WF program instance level, and custom) that can be specified within a tracking profile.

A comprehensive examination of the WF tracking infrastructure, including the nuts and bolts of the System.Workflow.Runtime.Tracking.SqlTracking-Service that stores tracking data in a SQL Server database, is outside the scope of this book; we suggest that you consult .NET Framework documentation and the WF SDK samples for more information. The basic ideas of WF program instance tracking, though, can be illustrated with a simple implementation of a custom tracking service that listens for all possible tracking events:

 using System; using System.Workflow.ComponentModel; using System.Workflow.Runtime; using System.Workflow.Runtime.Tracking; public class SimpleTrackingService : TrackingService {   private TrackingProfile profile;   public SimpleTrackingService()     : base()   {     profile = CreateTrackingProfile();   }   private TrackingProfile CreateTrackingProfile()   {     // Listen for activity status changes     ActivityTrackingLocation loc =       new ActivityTrackingLocation(typeof(Activity));     loc.ExecutionStatusEvents.Add(ActivityExecutionStatus.Initialized);     loc.ExecutionStatusEvents.Add(ActivityExecutionStatus.Executing);     loc.ExecutionStatusEvents.Add(ActivityExecutionStatus.Canceling);     loc.ExecutionStatusEvents.Add(ActivityExecutionStatus.Faulting);     loc.ExecutionStatusEvents.Add(ActivityExecutionStatus.Closed);     loc.ExecutionStatusEvents.Add(       ActivityExecutionStatus.Compensating);     loc.MatchDerivedTypes = true;     ActivityTrackPoint atp = new ActivityTrackPoint();     atp.MatchingLocations.Add(loc);     // Listen for workflow status events     WorkflowTrackPoint wtp = new WorkflowTrackPoint();     wtp.MatchingLocation = new WorkflowTrackingLocation();     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Aborted);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Changed);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Completed);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Created);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Exception);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Idle);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Loaded);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Persisted);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Resumed);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Started);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Suspended);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Terminated);     wtp.MatchingLocation.Events.Add(TrackingWorkflowEvent.Unloaded);     // Listen for custom tracking data     UserTrackingLocation loc2 = new UserTrackingLocation();     loc2.ActivityType = typeof(Activity);     loc2.MatchDerivedActivityTypes = true;     loc2.ArgumentType = typeof(object);     loc2.MatchDerivedArgumentTypes = true;     UserTrackPoint utp = new UserTrackPoint();     utp.MatchingLocations.Add(loc2);     // Return tracking profile     TrackingProfile profile = new TrackingProfile();     profile.Version = new Version(1, 0, 0, 0);     profile.ActivityTrackPoints.Add(atp);     profile.WorkflowTrackPoints.Add(wtp);     profile.UserTrackPoints.Add(utp);     return profile;   }   protected override bool TryGetProfile(Type workflowType,     out TrackingProfile profile)   {     profile = this.profile;     return true;   }   protected override TrackingChannel GetTrackingChannel(     TrackingParameters parameters)   {     return new SimpleTrackingChannel(parameters);   }   ... } 


Our custom tracking channel dutifully reports all tracking events that it receives to the console:

 public class SimpleTrackingChannel : TrackingChannel {   private TrackingParameters parameters;   public SimpleTrackingChannel(TrackingParameters parameters)     : base()   {     this.parameters = parameters;   }   protected override void Send(TrackingRecord record)   {     ActivityTrackingRecord r1 = record as ActivityTrackingRecord;     WorkflowTrackingRecord r2 = record as WorkflowTrackingRecord;     UserTrackingRecord r3 = record as UserTrackingRecord;     if (r1 != null)       Console.WriteLine(r1.QualifiedName + " (" + r1.ActivityType.Name + ") -> " + r1.ExecutionStatus);     else if (r2 != null)       Console.WriteLine(r2.TrackingWorkflowEvent);     else if (r3 != null)       Console.WriteLine(r3.QualifiedName + " (" + r3.ActivityType.Name + ") " + r3.UserDataKey + "= " + r3.UserData);   }   ... } 


To illustrate a custom tracking event, we can develop a very simple activity that uses the Activity.TrackData method to issue a string:

 using System; using System.Workflow.ComponentModel; namespace EssentialWF.Activities {   public class CallsTrackData : Activity   {     protected override ActivityExecutionStatus Execute(       ActivityExecutionContext context)     {       base.TrackData("Inside the CallsTrackData activity");       return ActivityExecutionStatus.Closed;     }   } } 


Before we execute a WF program that contains a CallsTrackData activity, we add an instance of our tracking service to the WF runtime:

  runtime.AddService(new SimpleTrackingService()); 


When we run a WF program, designed using the ensemble of custom activities we've developed during the course of this book, the console output looks like this:

 Created Started root (SimpleWFProgram) -> Executing par1 (Interleave) -> Executing seq1 (Sequence) -> Executing seq2 (Sequence) -> Executing w1 (WriteLine) -> Executing w3 (WriteLine) -> Executing One w1 (WriteLine) -> Closed Three w3 (WriteLine) -> Closed wait1 (Wait) -> Executing wait2 (Wait) -> Executing Idle wait2 (Wait) -> Closed w4 (WriteLine) -> Executing Four w4 (WriteLine) -> Closed seq2 (Sequence) -> Closed Idle wait1 (Wait) -> Closed w2 (WriteLine) -> Executing Two w2 (WriteLine) -> Closed seq1 (Sequence) -> Closed par1 (Interleave) -> Closed track1 (CallsTrackData) -> Executing track1 (CallsTrackData) = Inside the CallsTrackData activity track1 (CallsTrackData) -> Closed root (SimpleWFProgram) -> Closed Completed 


See if you can work out, from the tracking data reported by our tracking service, what the WF program must look like.




Essential Windows Workflow Foundation
Essential Windows Workflow Foundation
ISBN: 0321399838
EAN: 2147483647
Year: 2006
Pages: 97

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net