The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,502,635
since: 19 Jan 2005

CLINQ: Writing Continuous Queries Against Windows Workflow Foundation Tracking Services

posted Mon 14 Apr 08

If you've ever used Windows Workflow Foundation then you probably know that one of the most powerful features of WF is that you can track pretty much every single thing that takes place within a workflow with an excruciating amount of detail. This is especially handy in state machine workflows for being able to track when state transitions occur. Also, the ability to create your own tracking events (User Events) adds even more power to the already extremely useful system.

Out of the box, you can get a tracking service that logs the events to a SQL Server database. There are also code samples in the SDK that show you how to log all workflow activity to the console. I decided that I wanted to be able to bind my GUI to the list of events that have taken place throughout the lifetime of a given workflow instance. To do this, I wrote my own custom Workflow Tracking Service and added it to the workflow runtime instance as shown below:

_trackService = new ContinuousTrackingService();
_wfRuntime.AddService(_trackService);

Once the tracking service is in place, you're pretty much done. The WF runtime takes care of calling your service, obtaining a tracking channel, and trackintg things according to the tracking profile you provide. In my case, I wrote a channel that responds to the Send method call on the base tracking channel implementation, and add the tracking event to a published ContinuousCollection.

Once the workflow instance has started, my service is asked for a channel and then any time any event that the workflow runtime thinks is significant that matches the service's tracking profile (e.g. does it track just user data, or just activity data, or only workflow data, or some combination of those?) the channel's Send method is called.

With that in place, I can bind a listbox in my UI to a history of workflow tracking events like this:

_historyListBox.DataContext = _trackingService.TrackingLog;

And then really all I need to do is create a couple of data templates to display the right type of tracking entry (these are basic toss-outs that just make sure the system is working, your templates would obviously be much nicer looking):

<DataTemplate x:Key="userTrackingItemTemplate" 
DataType="{x:Type tracking:UserTrackingRecord}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Margin="0,0,8,0" Text="User Track:"/>
        <TextBlock Text="{Binding UserData}"/>
        <TextBlock Text="{Binding ActivityType}"/>
    </StackPanel>
</DataTemplate>
<DataTemplate x:Key="workflowTrackingItemTemplate"
DataType="{x:Type tracking:WorkflowTrackingRecord}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Margin="0,0,8,0" Text="WF Status:" />
        <TextBlock Text="{Binding TrackingWorkflowEvent}"/>
    </StackPanel>
</DataTemplate>
<DataTemplate x:Key="activityTrackingItemTemplate"
DataType="{x:Type tracking:ActivityTrackingRecord}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Margin="0,0,8,0" Text="Activity Type:" />
        <TextBlock Text="{Binding ActivityType}" Margin="0,0,8,0"/>
        <TextBlock Margin="0,0,8,0" Text="Status:" />
        <TextBlock Text="{Binding ExecutionStatus}"/>
    </StackPanel>
</DataTemplate>

With WPF, if you want a list box to dynamically choose which data template it is going to display based on some information contained within the row being displayed, then you need to create your own DataTemplateSelector. Here is the one I used:

public class TrackingLogDataTemplateSelector : DataTemplateSelector
{
    public override System.Windows.DataTemplate SelectTemplate(object item,
        System.Windows.DependencyObject container)
    {
        if (item is UserTrackingRecord)
            return Application.Current.MainWindow.FindResource(
"userTrackingItemTemplate") as DataTemplate;
        else if (item is WorkflowTrackingRecord)
            return Application.Current.MainWindow.FindResource(
"workflowTrackingItemTemplate") as DataTemplate;
        else if (item is ActivityTrackingRecord)
            return Application.Current.MainWindow.FindResource(
"activityTrackingItemTemplate") as DataTemplate;
        else
            return base.SelectTemplate(item, container);
    }
}

Even cooler than just binding my GUI to the entire tracking log is the ability to write continuous queries against the tracking log and then bind the GUI to the dynamically updated result set from those queries. Take this query, for example:

ContinuousCollection<TrackingRecord> filteredTrackingLog =
    from trackingRecord in _trackingService.TrackingLog
    where trackingRecord.EventDateTime >= targetTime
    select trackingRecord;

This query retrieves all events that took place within the workflow after a given target time. The possibilities for using queries against the tracking log are limited only by your imagination and the information contained within the tracking records.

So that's about it. If you like this idea, let me know and I will put the source code to the ContinuousTrackingService up on the CLINQ CodePlex site.

tags:        

links: digg this    del.icio.us    technorati    reddit




Tag Related Posts

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

CLINQ v1 Demo - Network Message Filtering

Wed 09 Jan 08 7:47 P GMT-05
tags:        

Continuous LINQ v1.0.0.0 Released

Tue 08 Jan 08 4:53 P GMT-05

Building a Ledger Style for WPF Grids

Tue 21 Aug 07 3:30 P GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Continuous LINQ

Mon 06 Aug 07 1:21 P GMT-05
tags:    

Ulysses Agenda Makes Redmond Developer News

Wed 29 Nov 06 7:10 P GMT-05
tags:                

Ulysses Agenda : First Cut Networking Design

Thu 14 Sep 06 12:46 A GMT-05
tags:                  

First Impressions of Windows Vista RC1

Thu 07 Sep 06 1:30 P GMT-05
tags:                      

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05