User Tasks
Der UserTaskClient ermöglicht das Abfragen und Bearbeiten von User Tasks aus BPMN-Prozessen.
Client erstellen
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);User Tasks abfragen
QueryAsync()
Fragt User Tasks mit Filtern ab:
using ProcessCube.Engine;
using ProcessCube.Engine.UserTasks;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
// Alle wartenden User Tasks abrufen
var userTasks = await client.QueryAsync(query => {
query.FilterByState(UserTaskState.Suspended);
});
Console.WriteLine($"Offene User Tasks: {userTasks.Count}");
foreach (var task in userTasks)
{
Console.WriteLine($" Task: {task.Name}");
Console.WriteLine($" ID: {task.Id}");
Console.WriteLine($" Prozess: {task.ProcessModelId}");
Console.WriteLine($" Form Fields: {task.Configuration.FormFields.Count}");
}Filter-Optionen
Nach ProcessInstanceId
var userTasks = await client.QueryAsync(query => {
query.FilterByProcessInstanceId("abc-123-def-456");
});Nach ProcessModelId
var userTasks = await client.QueryAsync(query => {
query.FilterByProcessModelId("ApprovalProcess");
query.FilterByState(UserTaskState.Suspended);
});Nach UserTaskId
var userTasks = await client.QueryAsync(query => {
query.FilterByUserTaskId("UserTask_Approve");
});UserTask Properties
| Property | Typ | Beschreibung |
|---|---|---|
Id | string | Eindeutige ID der User Task Instance |
UserTaskId | string | ID der User Task aus dem BPMN |
Name | string | Name der User Task |
State | UserTaskState | Aktueller Status |
ProcessInstanceId | string | Zugehörige Prozess-Instanz |
ProcessModelId | string | Prozessmodell-ID |
Configuration | UserTaskConfiguration | Form-Konfiguration |
Tokens | Dictionary<TokenType, Token> | Ein/Ausgabe-Tokens |
Form Fields auslesen
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
var userTasks = await client.QueryAsync(query => {
query.FilterByProcessInstanceId("abc-123");
query.FilterByState(UserTaskState.Suspended);
});
var userTask = userTasks.First();
Console.WriteLine($"User Task: {userTask.Name}");
Console.WriteLine("Form Fields:");
foreach (var field in userTask.Configuration.FormFields)
{
Console.WriteLine($" {field.Id}: {field.Type}");
Console.WriteLine($" Label: {field.Label}");
Console.WriteLine($" Required: {field.Required}");
}User Task abschließen
FinishUserTaskAsync()
using ProcessCube.Engine;
using ProcessCube.Engine.UserTasks;
var engineAddress = "http://localhost:8000";
var definitionsClient = ClientFactory.CreateProcessDefinitionsClient(engineAddress);
var userTaskClient = ClientFactory.CreateUserTaskClient(engineAddress);
// 1. Prozess starten (der User Task enthält)
var response = await definitionsClient.StartProcessInstanceAsync(
processModelId: "ApprovalProcess",
startEventId: "StartEvent_1",
initialToken: new { requestId = "REQ-456", amount = 5000.00m }
);
var processInstanceId = response.ProcessInstanceId;
Console.WriteLine($"Prozess gestartet: {processInstanceId}");
// 2. Warten bis User Task erscheint
await Task.Delay(2000);
// 3. User Task abrufen
var userTasks = await userTaskClient.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
query.FilterByState(UserTaskState.Suspended);
});
var userTask = userTasks.Single();
Console.WriteLine($"User Task gefunden: {userTask.Name}");
// 4. Input-Daten auslesen
var inputToken = userTask.Tokens[TokenType.OnEnter];
var input = inputToken.GetPayload<ApprovalInput>();
Console.WriteLine($"Request-ID: {input.RequestId}");
Console.WriteLine($"Amount: {input.Amount:C}");
// 5. Form Field-Werte setzen
var formField = userTask.Configuration.FormFields.First();
var formFieldValues = new Dictionary<string, object>
{
{ formField.Id, "Approved" }
};
var result = new UserTaskResult(formFieldValues);
// 6. User Task abschließen
await userTaskClient.FinishUserTaskAsync(userTask, result);
Console.WriteLine("User Task abgeschlossen");
internal sealed record ApprovalInput(string RequestId, decimal Amount);User Tasks können nur im Status Suspended abgeschlossen werden. Der Status wechselt zu Finished nach erfolgreichem Abschluss.
Typisierte Form Fields
using ProcessCube.Engine;
using ProcessCube.Engine.UserTasks;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
var userTasks = await client.QueryAsync(query => {
query.FilterByUserTaskId("UserTask_ReviewOrder");
query.FilterByState(UserTaskState.Suspended);
});
var userTask = userTasks.First();
// Input-Payload als typisiertes Objekt
var input = userTask.Tokens[TokenType.OnEnter].GetPayload<OrderReviewInput>();
Console.WriteLine($"Order-ID: {input.OrderId}");
Console.WriteLine($"Customer: {input.CustomerName}");
Console.WriteLine($"Items: {input.ItemCount}");
// Form Field-Werte typisiert setzen
var formData = new OrderReviewFormData(
Approved: true,
Comments: "Order looks good",
ReviewedBy: "reviewer@company.com"
);
var formFieldValues = new Dictionary<string, object>
{
{ "approved", formData.Approved },
{ "comments", formData.Comments },
{ "reviewedBy", formData.ReviewedBy }
};
var result = new UserTaskResult(formFieldValues);
await client.FinishUserTaskAsync(userTask, result);
Console.WriteLine("Order review completed");
internal sealed record OrderReviewInput(
string OrderId,
string CustomerName,
int ItemCount
);
internal sealed record OrderReviewFormData(
bool Approved,
string Comments,
string ReviewedBy
);User Task reservieren
ReserveAsync()
Reserviert eine User Task für einen bestimmten Benutzer:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
var userTaskId = "abc-123";
var userId = "user@company.com";
// User Task reservieren
await client.ReserveAsync(userTaskId, userId);
Console.WriteLine($"User Task für {userId} reserviert");CancelReservationAsync()
Hebt eine Reservierung auf:
await client.CancelReservationAsync(userTaskId);
Console.WriteLine("Reservierung aufgehoben");Batch-Verarbeitung
Mehrere User Tasks gleichzeitig verarbeiten:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
// Alle offenen Approval-Tasks
var userTasks = await client.QueryAsync(query => {
query.FilterByUserTaskId("UserTask_Approve");
query.FilterByState(UserTaskState.Suspended);
});
Console.WriteLine($"Verarbeite {userTasks.Count} Approval-Tasks...");
foreach (var task in userTasks)
{
try
{
// Input auslesen
var input = task.Tokens[TokenType.OnEnter].GetPayload<ApprovalInput>();
// Auto-Approval-Logik (z.B. für kleine Beträge)
if (input.Amount < 1000)
{
var formField = task.Configuration.FormFields.First();
var values = new Dictionary<string, object>
{
{ formField.Id, "Auto-Approved" }
};
await client.FinishUserTaskAsync(task, new UserTaskResult(values));
Console.WriteLine($" ✓ Auto-approved: {input.RequestId}");
}
else
{
Console.WriteLine($" ⏸ Manual review required: {input.RequestId}");
}
}
catch (Exception ex)
{
Console.WriteLine($" ✗ Error: {ex.Message}");
}
}
internal sealed record ApprovalInput(string RequestId, decimal Amount);Mit Authentifizierung
using ProcessCube.Engine;
using ProcessCube.Engine.Client.Identity;
var identityProvider = new ClientCredentialsIdentityProvider(
authorityAddress: "http://localhost:11235",
clientId: "usertask-service",
clientSecret: "secret-key",
scope: "engine_usertask"
);
var identity = await identityProvider.GetIdentityAsync();
var client = ClientFactory.CreateUserTaskClient(
engineAddress: "http://localhost:8000",
identity: identity
);
var userTasks = await client.QueryAsync(query => {
query.FilterByState(UserTaskState.Suspended);
});
Console.WriteLine($"User Tasks: {userTasks.Count}");ASP.NET Core API
using Microsoft.AspNetCore.Mvc;
using ProcessCube.Engine;
using ProcessCube.Engine.UserTasks;
[ApiController]
[Route("api/usertasks")]
public class UserTaskController : ControllerBase
{
private readonly IUserTaskClient _client;
public UserTaskController(IUserTaskClient client)
{
_client = client;
}
[HttpGet]
public async Task<IActionResult> GetUserTasks(
[FromQuery] string? processModelId = null)
{
var userTasks = await _client.QueryAsync(query => {
if (!string.IsNullOrEmpty(processModelId))
{
query.FilterByProcessModelId(processModelId);
}
query.FilterByState(UserTaskState.Suspended);
});
var result = userTasks.Select(t => new
{
t.Id,
t.Name,
t.ProcessModelId,
t.ProcessInstanceId,
formFields = t.Configuration.FormFields.Select(f => new
{
f.Id,
f.Label,
f.Type,
f.Required
})
});
return Ok(result);
}
[HttpPost("{userTaskId}/complete")]
public async Task<IActionResult> CompleteUserTask(
string userTaskId,
[FromBody] Dictionary<string, object> formValues)
{
try
{
// User Task abrufen
var userTasks = await _client.QueryAsync(query => {
query.FilterByUserTaskId(userTaskId);
query.FilterByState(UserTaskState.Suspended);
});
var userTask = userTasks.FirstOrDefault();
if (userTask == null)
{
return NotFound(new { error = "User Task nicht gefunden" });
}
// Abschließen
var result = new UserTaskResult(formValues);
await _client.FinishUserTaskAsync(userTask, result);
return Ok(new { message = "User Task abgeschlossen" });
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
}Fehlerbehandlung
using ProcessCube.Engine;
using ProcessCube.Engine.Client.Exceptions;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateUserTaskClient(engineAddress);
try
{
var userTasks = await client.QueryAsync(query => {
query.FilterByState(UserTaskState.Suspended);
});
Console.WriteLine($"Gefunden: {userTasks.Count} User Tasks");
}
catch (EngineClientException ex) when (ex.StatusCode == 401)
{
Console.WriteLine("Nicht authentifiziert");
}
catch (EngineClientException ex) when (ex.StatusCode == 403)
{
Console.WriteLine("Fehlende Berechtigung");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Verbindungsfehler: {ex.Message}");
}Best Practice: Verwenden Sie typisierte Records für Input-Payloads und Form-Daten, um Type Safety und IntelliSense zu erhalten.
Nächste Schritte
- Prozess starten - Prozesse mit User Tasks starten
- FlowNode Instances - User Task Execution History
- Prozess-Verwaltung - Zurück zur Übersicht