Aps2007

Hi,

I am creating a custom tracking service and I am overriding all the necessary members.

i.e. GetProfile(Guid), GetProfile(Type,Version), TryGetProfile, GetTrackingChannel, and TryReloadProfile.

When is the following version of GetProfile invoked

protected override TrackingProfile GetProfile(Guid workflowInstanceId)
{
// Returns the tracking profile for the specified workflow instance.
// This sample does not support reloading/instance profiles.
throw new NotImplementedException("The method or operation is not implemented.");
}

It is not getting called in my CustomTrackingService. I need the workflowInstanceId - InstanceId of the workflow for which the tracking service was requested.

In all the samples I found that GetProfile(Guid) is not implemented.

Thanks for your help.

Thanks,

Aparna



Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

This method is only invoked if you have updated a tracking profile for an individual workflow. If you never update profiles for specific instances this will never be called on your tracking service. If you want to see it in action create a workflow instance and call ReloadTrackingProfiles. This will trigger a call to all tracking services' TryReloadProfile(Type, Guid, out TrackingProfile). If you return true from this method (and provide a profile) you will have updated the profile for that instance. From that point forward the tracking runtime marks that instances as having a profile that is specific to the instance and not to the workflow type. If the instance is then unloaded and reloaded the tracking runtime will call the Guid overload of GetProfile.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Joel,


Thanks for your response but, it did not work for me.


Host application - Console Application.

//Create an instance of CustomTrackingServeice and add as a Service to workflowRuntime

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowTracking.Workflow1));

instance.ReloadTrackingProfiles();

instance.Start();


//CustomTrackingService

protected override bool TryGetProfile(Type workflowType, out TrackingProfile profile)

{

profile = null;

return false;

}

Exception : TrackingListener for instance %0 is not in cache. is returned in the host application.

TryReloadProfile(Type workflowType, Guid workflowInstanceId, out TrackingProfile profile) never gets called.



To clarify my scenario: I need workflowInstanceId to create a profile.
I want to track all public properties on activities in workflow based on their type.

I can do that if I provide InstanceId for workflow like this.


//Create a GUID for InstanceId

Guid myInstanceId = Guid.NewGuid();

//CreateWorkflow - provide InstanceId to it.

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowTracking.Workflow1), null, myInstanceId);

I can set the same instanceID on tracking service as a property on that and use it to create profile.

This method does not work if I use InvokeWorkflowActivity to invoke a child workflow, as there is no way of setting instanceID of child workflow and using it to create profile.

Help is needed.

Thanks,
Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

You need to be tracking something on the workflow first before you call ReloadTrackingProfiles. Sorry, I misunderstood and thought you were already had a profile associated and wanted to modify it. On possibility would be to always return a "default" profile from your TryGetProfile(Type, out TrackingProfile). This will associate the tracking runtime with the instance during the WorkflowRuntime.Create call. After Create returns you can reload the tracking profiles and generate a profile for the specific instance.

But to back up a bit - why do you need a workflowInstanceId to create a profile Are you creating a custom profile for each workflow If so does this need to be by instance Could it be by workflow type If you have a profile per type you'll get the instance id for each TrackingChannel that is requested.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Hi,

Little Progress since last time.

A valid profile should be provided in case of TryGetProfile(). In this profile I track everything of type(Activity).

//CustomTrackingService

protected override bool TryGetProfile(Type workflowType, out TrackingProfile profile)

{

profile = GetDefaultProfile(workflowType);

return true;

}

In host, call ReloadTrackingProfiles()

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowTracking.Workflow1));

instance.ReloadTrackingProfiles();

instance.Start();

This calls TryReloadProfile on instance.Start() and I can create profile based on specific InstanceId

protected override bool TryReloadProfile(Type workflowType, Guid workflowInstanceId, out TrackingProfile profile)

{

profile = GetProfile(workflowType, workflowInstanceId);

return true;

}

Till this point everything works.

The workflow being tracked uses InvokeWorkflowActivity to invoke child workflow. In this case how can I ask workflow instance to ReloadTrackingProfile(), since I do not get access to workflow instance being invoked from InvokeWorkflowActivity. So, the trackingservice only call TryGetProfile() and not TryReloadProfile() that I need.

Thanks for your help,

Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Joel ,

Thanks again for your response.

I want to extract values of all public properties of the activities in a workflow. For that I am creating profile as shown below based on workflowInstanceId. It works fine if InstanceId can be provided. Please point my mistake as I cant find.

private TrackingProfile GetProfile(Type workflowType, Guid wfInstanceId)

{

TrackingProfile profile = new TrackingProfile();

profile.Version = new Version(1, 0, 0);

profile = AddWorkflowTrackPoints(profile);

profile = AddActivityTrackPoints(profile, workflowType, wfInstanceId);

return profile;

}

private TrackingProfile AddActivityTrackPoints(TrackingProfile profile, Type wfType, Guid wfInstanceId)

{

//Get the WorkflowRuntime for the tracking service

WorkflowRuntime wfRuntime = this.Runtime;

//Get WorkflowInstance from Runtime given the InstanceID

WorkflowInstance wfInstance = wfRuntime.GetWorkflow(wfInstanceId);

//Get the workflow definition from the instance

CompositeActivity rootActivity = wfInstance.GetWorkflowDefinition() as CompositeActivity;

//Add ActivityTrackPoint for Root Activity and add WorkflowDataTrackingExtract to it.

if (rootActivity != null)

{

//Do not add any trackpoint if activity is disabled

if (rootActivity.Enabled == true)

{

ActivityTrackPoint trackPoint = GetActivityTrackPoint(rootActivity, profile);

if(trackPoint == null)

{

trackPoint = new ActivityTrackPoint();

ActivityTrackingLocation location = new ActivityTrackingLocation();

location.ActivityType = rootActivity.GetType();

//Match activity status event

location.ExecutionStatusEvents.Add(ActivityExecutionStatus.Executing);

location.ExecutionStatusEvents.Add(ActivityExecutionStatus.Closed);

location.ExecutionStatusEvents.Add(ActivityExecutionStatus.Faulting);

location.MatchDerivedTypes = true;

trackPoint.MatchingLocations.Add(location);

//Set the WorkflowDataTrackingExtract i.e properties to be extracted for rootActivity

Type workflowType = rootActivity.GetType();

//Get all public properties, declared by the instance of rootActivity.

//This does not include inherited properties.

PropertyInfo[] wfProperties = workflowType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);

if (wfProperties != null && wfProperties.Length > 0)

{

for (int propIndex = 0; propIndex < wfProperties.Length; propIndex++)

{

trackPoint.Extracts.Add(new WorkflowDataTrackingExtract(wfProperties[propIndex].Name));

}

}

//Add trackpoint to the profile

profile.ActivityTrackPoints.Add(trackPoint);

}

}

//Add ActivityTrackPoints for all activity type contained in the EnabledActivities

//Collection of rootActivity

//Get the EnabledActivities for the rootActivity

ReadOnlyCollection<Activity> enabledActivities = rootActivity.EnabledActivities;

foreach (Activity activity in enabledActivities)

{

//Get the ActivityTrackPoint if any for the activity type from the profile

ActivityTrackPoint activityTrackPoint = GetActivityTrackPoint(activity, profile);

//Create a new ActivityTrackPoint add a TrackingLocation for the specific activity type

if (activityTrackPoint == null)

{

activityTrackPoint = new ActivityTrackPoint();

ActivityTrackingLocation activityLocation = new ActivityTrackingLocation();

//Get Type for activity

Type type = activity.GetType();

activityLocation.ActivityType = type;

activityLocation.ExecutionStatusEvents.Add(ActivityExecutionStatus.Executing);

activityLocation.ExecutionStatusEvents.Add(ActivityExecutionStatus.Closed);

activityLocation.ExecutionStatusEvents.Add(ActivityExecutionStatus.Faulting);

activityLocation.MatchDerivedTypes = true;

//Add to MatchingLocations collection

activityTrackPoint.MatchingLocations.Add(activityLocation);

//Get all public properties, declared by the instance of activity

//This does not include the inherited properties

PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);

if (properties != null && properties.Length > 0)

{

for (int propIndex = 0; propIndex < properties.Length; propIndex++)

{

activityTrackPoint.Extracts.Add(new ActivityDataTrackingExtract(properties[propIndex].Name));

}

}

//Add the activityTrackPoint to the profile

profile.ActivityTrackPoints.Add(activityTrackPoint);

}

}

}

return profile;

}

Thanks ,

Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Hi,

I was able to create a profile for extracting properties based on workflowtype also. The only difference in the previous code

is the way workflowInstance is retrieved. Instead of getting workflowInstance using InstanceId. I could use GetLoadedWorkflows() and compare the name of instance to the workflowtype name.

This works for InvokeWorkflowActivity.

CompositeActivity rootActivity = null;

ReadOnlyCollection<WorkflowInstance> wfInstances = wfRuntime.GetLoadedWorkflows();

foreach (WorkflowInstance loadedWfInstance in wfInstances)

{

CompositeActivity loadedRootActivity = loadedWfInstance.GetWorkflowDefinition() as CompositeActivity;

String wfName = loadedRootActivity.Name;

Console.WriteLine("Loaded Instance Name : " + wfName);

if (loadedRootActivity.QualifiedName.Equals(wfType.Name))

{

rootActivity = loadedRootActivity;

Console.WriteLine("Returned RootActivity : "+loadedRootActivity .Name);

break;

}

}

if (rootActivity == null)

{

String wfName = wfType.Name;

throw new Exception("Workflow runtime cannot find the Workflow instance for "+wfName);

}

It DOES NOT work if I use Xaml Activation to create a child workflow from Execute of myCustom activity.

Suppose the xoml is:

<SequenceActivity x:Name="XomlActivity" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">

<DelayActivity TimeoutDuration="00:00:05" x:Name="xomldelayActivity1" />

<DelayActivity TimeoutDuration="00:00:10" x:Name="XdelayActivity2" />

</SequenceActivity>

Then in GetProfile(Type WorkflowType) the WorkflowType comes as SequenceActivity and its name also SequenceActivity .

So my logic of getting all workflowInstances from runtime and picking the correct one base on workflow Name does not work. Moreover, I think WorkflowInstanceId is a better identifer for WorkflowInstance than its name.

Sorry for the long long post, but I could not explain in short.

Thanks again,

Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

In general the tracking framework is based around profiling workflows on a per definition or type basis. InstanceId isn't a workflow definition identifier - it is the identifier for a specific instance of a workflow of a given type. Generating a profile for all instances of the same workflow type will get unmanageable rather quickly (unless there really is something specific to that instance that you need to track; this doesn't seem to be the case here).

However it sounds like generating the profiles on a per type basis works for you with a couple of problems. I agree that Name isn't a great identifier. Type is the identifier that you should use (AssemblyQualifiedName for a string representation). This is how the SqlTrackingService identifies profiles for specific workflow types.

The Xoml based scenario does however present some problems. As you have found the type of any Xoml based workflow (whether you create it via WorkflowRuntime.Create or the Invoke activity) is based on the type of the root element. One possibility here is to hash the Xoml to an identifier. You could also hash AssemblyQualifiedName and then you'd have one identifier type for you profile management system.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Joel,

Thanks for your response.

How can we extract runtime values of all public properties defined for all activities in a workflow
Tracking seemed like a solution to me.

For that we need to create a profile that specifies extract based on the workflow defintion for the particular instance of workflow. If I create a profile just based on type Activity (ActivityTrackPoint with ActivityTrackingLocation activityLocation = new ActivityTrackingLocation(typeof(Activity)) then in extracts (activityTrackPoint.Extracts)

I dont get names of properties defined on a particular type of activity. I just get the properties defined for "Type Activity".

for e.g. My workflow contains a Delay Activity, I want to track its properties.
It has a property named - TimeoutDuration. This property is not defined on Type Activity so I cannot get its name and add it to extract when profile is created.


For this I need WorkflowDefinition from WorkflowInstance. The WorkflowDefinition will have metadata for the activity tree of the workflow. So I can get access to Type of Activity and call GetProperties() on the Type of Activity.

PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);

You mentioned that I can hash AssemblyQualifiedName to create identifier for Workflowtype.


How does this identifier help to get access to WorkflowInstance from WorkflowRuntime

The WorkflowRuntime is available on TrackingService - Runtime property. WorkflowRuntime has two methods that return access to WorkflowInstance.

1Smile GetWorkflow(Guid WorkflowInstanceId)

2Smile GetLoadedWorkflows() and comparing the type name to get the correct instance.
Option 1 does not work if there is a InvokeWorkflowActivity used to invoke child workflow.
Option 2 does not work in case of Xoml Activation used to invoke a workflow.

Clarification: The problem is how to find what properties are available on each activity type. The workflow may contain custom activities containing custom properties not available with generic Type Activity.

How do I get activities data i.e its properties at runtime , both for main workflow and child workflow

Is there any other solution, other than Tracking

Any help is highly appreciated.
Thanks Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

Tracking is the way to accomplish this but you need to build a custom tracking profile per workflow type/definition. When the tracking runtime call TryGetProfile(Type type, out TrackingProfile) the type parameter is the type of the workflow being run. From this type you need to walk the activities in the workflow, reflect over them and get a list of all public properties. You then need to create an ActivityTrackPoint for each unique type that you see (in other words if there is more than 1 Delay in the workflow tree you should only create 1 ActivityTrackPoint with a type of DelayActivity). For each ActivityTrackPoint that you create add an extract for each public property. Don't add any conditions to the track points. Add all the track points to the profile, save the profile somewhere (so that you don't have to redo all the reflection and profile building work every time an instance of the same workflow type runs) and then return the profile via the out TrackingProfile parameter.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

Aps2007

Joel,

Thanks again. I already have tried this.

"When the tracking runtime call TryGetProfile(Type type, out TrackingProfile) the type parameter is the type of the workflow being run. From this type you need to walk the activities in the workflow, reflect over them and get a list of all public properties."

From object of type Type we cannot walk the activities in the workflow. It does not contain the Activities collection. We need actual instance of the activity and then get the Type of it using GetType() and reflect upon it and so we can read the public properties. This thread also includes the code for it.

So the type parameter in TryGetProfile(Type type, out TrackingProfile) does not work.

I can send you the entire project code if that is OK with you.

Thanks,

Aparna





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

You can get this from the type by creating an instance of the Activity in order to examine the activity tree. You can do this from the type of workflow that is passed to you (except in the Xoml case, see below):

Activator.CreateInstance(workflowType) as Activity;

You can then upcast to CompositeActivity and, if successful, walk the Activities collection and reflect over the public properties of each activity.

Xoml is more difficult to do this on the fly due to the typically workflow type. The easiest thing to do is to do this after the instance is created. This gets back to my previous comment above about initially returning a generic or default profile for Xoml based workflow. Something like the following:

  1. WorkflowRuntime.CreateInstance - this will call into your tracking service's TryGetProfile. If this is a Xoml workflow (identified by the type or perhaps by creating an instance as above and checking the count of items in the Activities collection) you should return a simple profile but not one that has all of the details that you want because they won't be available based simply on the type.
  2. After CreateInstance returns call WorkflowInstance.GetWorkflowDefinition. Upcast to CompositeActivity and walk the Activities collection as you would do for a non xoml based workflow and create a profile. This will have all of the child activities defined in the xoml document.
  3. Save this profile somewhere.
  4. Call WorkflowInstance.ReloadProfile. This will in turn call TryReloadProfile on your tracking service. Return the profile that you saved in step 3.
  5. Call WorkflowInstance.Start.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights





Re: Windows Workflow Foundation TrackingService GetProfile(Guid workflowInstanceId)

jdw - MSFT

Sorry, I just saw your other post which reminded me that you are trying to do this via the InvokeActivity and Xoml which doesn't give you access to the created workflow (so you can't do the steps above in this case). I don't have a great solution for that. My best suggestion is for the combination of things you're trying to do would be to not use Xoml based workflow definitions for InvokeActivity. If I can think of any more ideas I'll post them to this thread.

Thanks,
Joel West
MSFTE - SDE

This posting is provided "AS IS" with no warranties, and confers no rights