Here is the first of the series of articles about the Workflow Manager I promised.

 

First let me start with a bit of history. Before joining the WF team I was a dev on the Biztalk tracking/management team and so I had some ideas on how to design user experience around managing workflows. I have started working on the app back in December 2004 and originally it had two processes – one hosting the Runtime and the other – UI application. I was using .Net Remoting as communication link between the two. Later I got rid of the Remoting to simplify life a bit (both the runtime and the UI now run in the same process) but some of that stuff is still in the code, namely the AdministrationService and the AdministrationServiceProxy classes that are being used on the host/UI sides respectively to channel events and calls between the two.

 

Now let get into the architecture overview and then will drill into interesting pieces one by on in the later posts. As I said before the sample consist of two forms – one hosts the WF runtime (WinOEHost) and the other is the main client app form (WorkflowManager).

 

The list view of the main client form (DataGridViewExplore) is a subclass of the new managed DataGridView control. It custom paints all list entries in the Office Outlook two-line format. The data is being provided by the WorkflowInstanceManager which implements IBindingList interface to dynamically notify its clients about changes in the list. Based on the user selection in the Workflows tree view (either Live or Tracked), the WorkflowInstanceManager would pull the data from either the AdministrationServiceProxy or SQLTrackingDataProvider, both of which implement IDataProvider. In case of the Live data selected, it would also sink state change events (which include instance create/completed/terminated/etc and activity started/completed/etc). Both data providers return a list of IWorkflowInstance objects.

 

Let’s drill into the Live data case a little deeper. AdministrationService uses a custom tracking service TrackingEventsHelper that in its tracking profile asks for all activity state change events for all activities in the workflow. These events are then cached in memory for every live workflow in the corresponding instance of the LiveWorkflowInstance class. This class is a wrapper around the WF’s WorkflowInstance class and adds ability to 1) store and return by a request a list of prior activity state change events, 2) serialize current workflow definition into markup (with some workarounds for the custom root activity case) and 3) simplifies applying a batch of workflow changes supplied by the UI client.

 

The details view uses the ViewHost control to show workflow in a graphical form. There is a little trick in the WorkflowDesignSurface to have the design surface in the read-only or read-write form – take a look at MakePropertiesReadOnly(IServiceProvider, object) function to see how it’s done.

 

The UI-driven dynamic updates are enabled by the DynamicUpdateDriver class that sinks ComponentChanged events and adds an instance of the ActivityDynamicChangeLog for every component changed action performed by the user.

 

That’s basically the birds-eye view of the application.