Skip to main content

InstanceService.GetInstanceActivities

Reference

PagedData<InstanceActivity> GetInstanceActivities(Guid instanceId, ActivityQuery activityQuery)

Use GetInstanceActivities to retrieve a chronological list of activities and events that have occurred on a specific Protrak instance. This API is commonly used for tracking instance history, generating audit trails, and analyzing workflow patterns.

Parameters

  • instanceId: The unique identifier of the instance for which to retrieve activity history.
  • activityQuery: Query object containing activity filtering criteria and pagination settings:
    • Type: Optional activity type filter. Use ActivityType.ActionPromoted for state transitions, ActivityType.MessagePosted for messages, or 0 for all activity types.
    • StartDate, EndDate: Optional date range filters to limit activities to a specific time period.
    • Skip, Take: Pagination parameters for result set. Default: Skip = 0, Take = 100.
    • IsSortByDescending: Optional flag to control sort order. Default is true (newest first).

Returns

PagedData<InstanceActivity>:

  • Collection of InstanceActivity objects representing activities for the specified instance.
  • Each InstanceActivity contains details about the activity performed.
  • Includes pagination metadata (TotalCount, Skip, Take).
  • Returns empty collection if no activities are found.

Error Handling & Caveats

  • If the instance does not exist or the user lacks permission to view it, an AccessDeniedException is thrown.
  • If the instanceId is empty or invalid, an ArgumentException is thrown.
  • If date range filters are invalid (StartDate > EndDate), results may be empty.
  • The API enforces access control and only returns activities the current user has permission to view.
  • Message activities and standard activities are merged when Type = 0 (all activities).
  • EndTime for the most recent activity is set to the current UTC time.
  • For large activity histories, consider using appropriate pagination to optimize performance.

Usage

try {
// Get all promotion activities for the last 30 days
var activityQuery = new ActivityQuery {
Type = ActivityType.ActionPromoted,
StartDate = DateTime.UtcNow.AddDays(-30),
EndDate = DateTime.UtcNow,
Skip = 0,
Take = 100,
IsSortByDescending = true
};

var activities = InstanceService.GetInstanceActivities(instanceId, activityQuery);

Console.WriteLine($"Found {activities.TotalCount} promotion activities in the last 30 days");
foreach (var activity in activities.Items) {
Console.WriteLine($"{activity.StartTime:yyyy-MM-dd HH:mm} - {activity.ActivityType}");
Console.WriteLine($" From: {activity.FromState?.Name} -> To: {activity.ToState?.Name}");
Console.WriteLine($" User: {activity.UserName}");
if (activity.EndTime.HasValue) {
var duration = activity.EndTime.Value - activity.StartTime;
Console.WriteLine($" Duration: {duration.TotalHours:F1} hours");
}
}
} catch (AccessDeniedException ex) {
Console.WriteLine("Access denied: " + ex.Message);
} catch (ArgumentException ex) {
Console.WriteLine("Invalid parameters: " + ex.Message);
}

Example: Getting Recent Promotion Activities

try {
// Most common pattern - get recent state transitions for reporting
var activityQuery = new ActivityQuery {
Type = ActivityType.ActionPromoted,
IsSortByDescending = false, // Chronological order
Take = int.MaxValue // Get all activities
};

var activities = InstanceService.GetInstanceActivities(taskId, activityQuery);

if (activities?.Items != null && activities.Items.Any()) {
Console.WriteLine($"Task progression history:");
foreach (var activity in activities.Items) {
var fromState = activity.FromState?.Name ?? "Created";
var toState = activity.ToState?.Name ?? "Unknown";
Console.WriteLine($"- {activity.StartTime:yyyy-MM-dd}: {fromState} → {toState}");

if (activity.EndTime.HasValue) {
var timeInState = activity.EndTime.Value - activity.StartTime;
Console.WriteLine($" Time in {toState}: {timeInState.TotalDays:F1} days");
}
}
} else {
Console.WriteLine("No promotion activities found for this task");
}
} catch (Exception ex) {
Console.WriteLine($"Error retrieving activities: {ex.Message}");
}

Example: Validating Instance State History

try {
// Common pattern in pre-delete triggers - check for specific activities
var activityQuery = new ActivityQuery {
Type = ActivityType.ActionPromoted,
Take = 0 // Only need count, not actual data
};

var activities = InstanceService.GetInstanceActivities(instanceId, activityQuery);

if (activities != null && activities.TotalCount > 1) {
throw new Exception("Delete operation is not allowed after task has been submitted.");
}

Console.WriteLine("Instance can be safely deleted - no promotion history found");
} catch (Exception ex) {
Console.WriteLine($"Validation error: {ex.Message}");
}

Example: Calculating Time Spent in Each State

try {
var activityQuery = new ActivityQuery {
Type = ActivityType.ActionPromoted,
IsSortByDescending = false, // Chronological order for calculations
Take = int.MaxValue
};

var activities = InstanceService.GetInstanceActivities(projectId, activityQuery);

if (activities?.Items != null && activities.Items.Any()) {
Console.WriteLine("Time spent in each state:");

foreach (var activity in activities.Items) {
var stateName = activity.ToState?.Name ?? "Unknown State";
var timeInState = TimeSpan.Zero;

if (activity.EndTime.HasValue) {
timeInState = activity.EndTime.Value - activity.StartTime;
} else {
// Current state - calculate time from start to now
timeInState = DateTime.UtcNow - activity.StartTime;
}

Console.WriteLine($"- {stateName}: {timeInState.TotalDays:F1} days");
}

// Calculate total processing time
if (activities.Items.Any()) {
var firstActivity = activities.Items.First();
var lastActivity = activities.Items.Last();
var totalTime = DateTime.UtcNow - firstActivity.StartTime;
Console.WriteLine($"\nTotal processing time: {totalTime.TotalDays:F1} days");
}
}
} catch (Exception ex) {
Console.WriteLine($"Error calculating state durations: {ex.Message}");
}

Troubleshooting

  • If AccessDeniedException occurs, ensure the current user has permission to view the instance and its activity history.
  • If date range queries return unexpected results, verify that StartDate is earlier than EndDate and dates are in UTC format.
  • For performance issues with large activity histories, use appropriate pagination with reasonable Take values instead of int.MaxValue.
  • If specific activity types are missing, verify that the Type parameter matches the expected ActivityType enum values.
  • When calculating state durations, always check if EndTime has a value - the most recent activity may not have an end time.
  • Use Take = 0 when you only need the total count of activities without retrieving the actual data.
  • For audit and compliance requirements, ensure all activity types are captured by using Type = 0 and appropriate date ranges.
  • The API returns activities based on the current user's permissions - system/admin users may see more activities than regular users.
  • Always handle the case where activities?.Items might be null or empty before iterating.
  • For reporting scenarios, use IsSortByDescending = false to get chronological order for timeline analysis.
  • Activity EndTime is calculated based on the next activity's StartTime - the current state activity will have null EndTime.