I 'm trying to capture trace for argument named "arg1" and i use this tracking profile
private MyTrace CreateTrace()
{
string all="*"
MyTrace trace = new MyTrace();
trace.TrackingProfile = new TrackingProfile()
{
ImplementationVisibility = ImplementationVisibility.All,
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
// Limit workflow instance tracking records for started and completed workflow states
States = {WorkflowInstanceStates.Started, WorkflowInstanceStates.Completed }
},
ActivityStateQuery query = new ActivityStateQuery()
new ActivityStateQuery()
{
ActivityName = "*",
States = { ActivityStates.Executing ,ActivityStates.Closed},
Arguments={"arg1"}
}
}
};
return trace;
}
Activity to trace : (It's very simple arg1="value")
<Activity mc:Ignorable="sap" x:Class="WorkflowConsoleApplication5.Workflow1" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System"
xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:s1="clr-namespace:System;assembly=System"
xmlns:s2="clr-namespace:System;assembly=System.Xml"
xmlns:s3="clr-namespace:System;assembly=System.Core"
xmlns:s4="clr-namespace:System;assembly=System.ServiceModel"
xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities"
xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities"
xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"
xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System"
xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel"
xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core"
xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:sd="clr-namespace:System.Data;assembly=System.Data"
xmlns:sl="clr-namespace:System.Linq;assembly=System.Core"
xmlns:st="clr-namespace:System.Text;assembly=mscorlib"
xmlns:w="clr-namespace:WorkflowConsoleApplication5"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="arg1" Type="InArgument(x:String)" />
</x:Members>
<sap:VirtualizedContainerService.HintSize>654,676</sap:VirtualizedContainerService.HintSize>
<mva:VisualBasic.Settings>Assembly references and imported namespaces for internal implementation</mva:VisualBasic.Settings>
<Flowchart sap:VirtualizedContainerService.HintSize="614,636">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">False</x:Boolean>
<av:Point x:Key="ShapeLocation">270,2.5</av:Point>
<av:Size x:Key="ShapeSize">60,75</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,77.5 300,171</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Flowchart.StartNode>
<FlowStep x:Name="__ReferenceID0">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">179,171</av:Point>
<av:Size x:Key="ShapeSize">242,58</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,229 300,259 290,259 290,299.5</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Assign sap:VirtualizedContainerService.HintSize="242,58">
<Assign.To>
<OutArgument x:TypeArguments="x:String">[arg1]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">value</InArgument>
</Assign.Value>
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
</Assign>
<FlowStep.Next>
<FlowStep x:Name="__ReferenceID1">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">184.5,299.5</av:Point>
<av:Size x:Key="ShapeSize">211,61</av:Size>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<WriteLine sap:VirtualizedContainerService.HintSize="211,61" Text="[arg1]">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
</WriteLine>
</FlowStep>
</FlowStep.Next>
</FlowStep>
</Flowchart.StartNode>
<x:Reference>__ReferenceID0</x:Reference>
<x:Reference>__ReferenceID1</x:Reference>
</Flowchart>
</Activity>
public class MyTrace : TrackingParticipant
{
private String participantName = "Mytrace";
protected override void Track(TrackingRecord record, TimeSpan timeout)
{
Console.WriteLine("*{0}+++++++++++++++++++++++++++++++++++++",record.RecordNumber);
Console.Write(String.Format(CultureInfo.InvariantCulture, "{0} emitted trackRecord: {1} Level: {2}, RecordNumber: {3}", participantName, record.GetType().FullName, record.Level, record.RecordNumber));
WorkflowInstanceRecord workflowInstanceRecord = record as WorkflowInstanceRecord;
if (workflowInstanceRecord != null)
{
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
" Workflow InstanceID: {0} Workflow instance state: {1}",
record.InstanceId, workflowInstanceRecord.State));
}
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
IDictionary<String, object> variables = activityStateRecord.Variables;
IDictionary<string, object> arguments = activityStateRecord.Arguments;
StringBuilder vars = new StringBuilder();
if (variables.Count > 0)
{
vars.AppendLine("\n\tVariables:");
foreach (KeyValuePair<string, object> variable in variables)
{
vars.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", variable.Key, variable.Value));
}
}
StringBuilder args = new StringBuilder();
if (arguments.Count > 0)
{
args.AppendLine("\n\tArguments:");
foreach (KeyValuePair<string, object> arg in arguments)
{
args.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", arg.Key, arg.Value));
}
}
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
" :Activity DisplayName: {0} :ActivityInstanceState: {1} {2} {3}",
activityStateRecord.Activity.Name, activityStateRecord.State,
((variables.Count > 0) ? vars.ToString() : String.Empty),
((arguments.Count > 0) ? args.ToString() : String.Empty)));
}
CustomTrackingRecord customTrackingRecord = record as CustomTrackingRecord;
if ((customTrackingRecord != null) && (customTrackingRecord.Data.Count > 0))
{
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"\n\tUser Data:"));
foreach (string data in customTrackingRecord.Data.Keys)
{
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
" \t\t {0} : {1}", data, customTrackingRecord.Data[data]));
}
}
Console.WriteLine();
}
}
When i execute activity(Workflow1) , i recive this trace ouput:
*0+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.WorkflowInstanceRecord Level: Info, RecordNumber: 0 Workflow InstanceID: a5b135ce-03d0-40ea-a491-15ff01030e05 Workflow instance state: Starte
*1+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 1 :Activity DisplayName: Workflow1 :ActivityInstanceState: Executing
Arguments:
Name: arg1 Value: HOLA
*2+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 2 :Activity DisplayName: Flowchart :ActivityInstanceState: Executing
*3+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 3 :Activity DisplayName: Assign :ActivityInstanceState: Executing
*4+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 4 :Activity DisplayName: Assign :ActivityInstanceState: Closed
value
*5+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 5 :Activity DisplayName: WriteLine :ActivityInstanceState: Executing
*6+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 6 :Activity DisplayName: WriteLine :ActivityInstanceState: Closed
*7+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 7 :Activity DisplayName: Flowchart :ActivityInstanceState: Closed
*8+++++++++++++++++++++++++++++++++++++
TrackingParticipant emitted trackRecord: System.Activities.Tracking.ActivityStateRecord Level: Info, RecordNumber: 8 :Activity DisplayName: Workflow1 :ActivityInstanceState: Closed
Arguments:
Name: arg1 Value: value
*9+++++++++++++++++++++++++++++++++++++
Why argument (arg1) only notify changed when Workflow1 is closed? Whats happend with assing arg1="value"? I think it must notify argument was changed
Use the tracking participant created by Ron Jacobs. It's really easy to query after the activity has run because it has structured results and you'll be able to pick up that argument at every stage actually. It actually uses the Microsoft.Activities.UnitTesting framework for the participant. This participant can actually track child workflows at the same time as well!
Here are some blog articles where Ron explains how to use it.
http://blogs.msdn.com/b/rjacobs/archive/2011/01/13/wf4-how-tracking-helped-me-write-a-unit-test.aspx
http://blogs.msdn.com/b/rjacobs/archive/2011/05/26/tracking-child-workflow-with-invokeworkflow.aspx
http://blogs.msdn.com/b/rjacobs/archive/2012/06/18/what-state-is-my-statemachine-in.aspx
I am editing this to clarify that if you must get more frequent updates you'll need to track a variable and not the argument. So, set the value of a variable to that of the argument, and then if you need to before leaving the workflow, set the value of the argument to that of the variable but setting the InArgument at the end of the workflow is really of none effect because nobody is going to be using it (at least I'm assuming).