Skip to Content
DocsClientsDotnet.NET Client

.NET Client

Der ProcessCube® .NET Client ist eine vollständige C# Library für die Integration mit der ProcessCube® Engine. Sie unterstützt .NET Core, .NET Framework und bietet eine moderne, asynchrone API mit vollem Async/Await-Support.

Überblick

Der .NET Client ermöglicht die nahtlose Integration von ProcessCube® Prozessen in .NET-Anwendungen. Mit vollständiger C#-Typisierung, LINQ-Support und modernem async/await ist er ideal für Enterprise-Anwendungen, Microservices und Windows-Services.

Hauptfeatures

  • Vollständige C#-Typisierung: IntelliSense und Compile-Time Type-Safety
  • Async/Await: Moderne asynchrone API mit Task-basiertem Muster
  • .NET Core & Framework: Läuft auf beiden Plattformen
  • OAuth 2.0 Support: Integration mit ProcessCube® Authority
  • External Task Workers: Mit Hosting-Integration für ASP.NET Core
  • Dependency Injection: Vollständige DI-Unterstützung
  • Serialization: Anpassbare JSON-Serialisierung

Installation

NuGet Package Manager

dotnet add package ProcessCube.Client

Package Manager Console

Install-Package ProcessCube.Client

.csproj File

<ItemGroup> <PackageReference Include="ProcessCube.Client" Version="1.0.0" /> </ItemGroup>

Der .NET Client benötigt .NET Core 6.0+ oder .NET Framework 4.7.2+.

Quick Start

Client erstellen

Der einfachste Weg, einen Client zu erstellen:

using ProcessCube.Client; // Client ohne Authentifizierung (nur für lokale Entwicklung) var client = new ProcessCubeClient("http://localhost:8000");

Mit Authentifizierung

Für produktive Umgebungen mit ProcessCube® Authority:

using ProcessCube.Client; using ProcessCube.Client.Authentication; var credentials = new ClientCredentials { ClientId = "your-client-id", ClientSecret = "your-client-secret", AuthorityUrl = "http://localhost:11235" }; var client = new ProcessCubeClient("http://localhost:8000", credentials);

Prozess starten

Ein einfaches Beispiel zum Starten eines Prozesses:

// Prozess ohne Parameter starten var result = await client.StartProcessAsync("MyProcessKey"); Console.WriteLine($"Process started: {result.ProcessInstanceId}");

Mit Parametern starten

// Prozess mit Eingabeparametern starten var inputValues = new Dictionary<string, object> { ["customerName"] = "Max Mustermann", ["orderAmount"] = 1500 }; var result = await client.StartProcessAsync("OrderProcess", inputValues); Console.WriteLine($"Process Instance ID: {result.ProcessInstanceId}"); Console.WriteLine($"Result: {result.Result}");

Wichtige Konzepte

Prozess-Management

Application Info abrufen

// Engine-Informationen abrufen var info = await client.GetApplicationInfoAsync(); Console.WriteLine($"Engine Version: {info.Version}"); Console.WriteLine($"Engine URL: {info.Url}");

Prozesse abfragen

// Alle deployten Prozesse abrufen var processes = await client.GetProcessesAsync(); foreach (var process in processes) { Console.WriteLine($"{process.Key}: {process.Name}"); }

Prozess-Instanzen abfragen

using ProcessCube.Client.Models; // Laufende Prozess-Instanzen abrufen var query = new ProcessInstanceQuery { ProcessKey = "OrderProcess", State = ProcessInstanceState.Running }; var instances = await client.GetProcessInstancesAsync(query); foreach (var instance in instances) { Console.WriteLine($"Instance: {instance.ProcessInstanceId}"); Console.WriteLine($"State: {instance.State}"); }

User Task Handling

User Tasks abrufen

// Alle offenen User Tasks abrufen var userTasks = await client.GetUserTasksAsync(); // Nach Prozess-Instanz filtern var tasksForInstance = await client.GetUserTasksAsync(new UserTaskQuery { ProcessInstanceId = "instance-123" }); foreach (var task in userTasks) { Console.WriteLine($"Task: {task.Id}"); Console.WriteLine($"Name: {task.Name}"); }

User Task abschließen

// User Task mit Ergebnis abschließen var resultData = new Dictionary<string, object> { ["approved"] = true, ["comment"] = "Genehmigt durch Manager" }; await client.FinishUserTaskAsync(task.Id, resultData);

External Task Pattern

Manuelles External Task Handling

// External Tasks abrufen und verarbeiten var externalTasks = await client.FetchAndLockExternalTasksAsync( topicName: "SendEmail", workerId: "worker-1", maxTasks: 5 ); foreach (var task in externalTasks) { try { // Task-Parameter auslesen var recipient = task.Variables["recipient"].ToString(); var subject = task.Variables["subject"].ToString(); var body = task.Variables["body"].ToString(); // E-Mail versenden (Pseudo-Code) await SendEmailAsync(recipient, subject, body); // Task als erfolgreich abgeschlossen markieren var result = new Dictionary<string, object> { ["success"] = true, ["sentAt"] = DateTime.UtcNow }; await client.CompleteExternalTaskAsync(task.Id, "worker-1", result); } catch (Exception ex) { // Task als fehlgeschlagen markieren await client.HandleExternalTaskBpmnErrorAsync( task.Id, "worker-1", "EMAIL_SEND_ERROR", ex.Message ); } }

External Task Workers mit Hosting

Für ASP.NET Core-Anwendungen:

using ProcessCube.Client.ExternalTasks; using Microsoft.Extensions.DependencyInjection; // In Startup.cs oder Program.cs services.AddProcessCubeClient(options => { options.EngineUrl = "http://localhost:8000"; options.ClientId = "my-service"; options.ClientSecret = "secret-key"; options.AuthorityUrl = "http://localhost:11235"; }); services.AddExternalTaskWorker<EmailWorker>("SendEmail"); // Worker-Klasse public class EmailWorker : IExternalTaskWorker { private readonly IEmailService _emailService; public EmailWorker(IEmailService emailService) { _emailService = emailService; } public async Task<IDictionary<string, object>> ExecuteAsync( ExternalTask task, CancellationToken cancellationToken) { var recipient = task.Variables["recipient"].ToString(); var subject = task.Variables["subject"].ToString(); var body = task.Variables["body"].ToString(); await _emailService.SendAsync(recipient, subject, body); return new Dictionary<string, object> { ["success"] = true, ["sentAt"] = DateTime.UtcNow }; } }

External Task Workers mit Hosting-Integration laufen als Background-Service und pollen die Engine automatisch.

Event Handling

Signal senden

// Signal an laufende Prozesse senden await client.SendSignalAsync( "PaymentReceived", new Dictionary<string, object> { ["orderId"] = "ORDER-123", ["amount"] = 1500 } );

Message senden

// Message an spezifische Prozess-Instanz senden await client.SendMessageAsync( "UpdateOrder", new Dictionary<string, object> { ["status"] = "shipped", ["trackingNumber"] = "TRACK-456" }, processInstanceId: "instance-123" );

Authentifizierung

Client Credentials Flow

Für Service-to-Service Kommunikation:

var credentials = new ClientCredentials { ClientId = "my-service", ClientSecret = "secret-key", AuthorityUrl = "http://localhost:11235" }; var client = new ProcessCubeClient("http://localhost:8000", credentials); // Client authentifiziert sich automatisch beim ersten Request var processes = await client.GetProcessesAsync();

Mit User Token

Für Benutzer-Anwendungen:

var authOptions = new AuthorizationCodeOptions { ClientId = "my-app", AuthorityUrl = "http://localhost:11235", RedirectUri = "http://localhost:5000/callback", Scopes = new[] { "openid", "profile", "engine_read", "engine_write" } }; var client = new ProcessCubeClient("http://localhost:8000", authOptions); // Login-Flow initiieren await client.LoginAsync();

Dependency Injection

ASP.NET Core Integration

using ProcessCube.Client; using Microsoft.Extensions.DependencyInjection; // In Startup.cs oder Program.cs public void ConfigureServices(IServiceCollection services) { services.AddProcessCubeClient(options => { options.EngineUrl = Configuration["ProcessCube:EngineUrl"]; options.ClientId = Configuration["ProcessCube:ClientId"]; options.ClientSecret = Configuration["ProcessCube:ClientSecret"]; options.AuthorityUrl = Configuration["ProcessCube:AuthorityUrl"]; }); services.AddControllers(); } // In einem Controller [ApiController] [Route("api/[controller]")] public class ProcessController : ControllerBase { private readonly IProcessCubeClient _client; public ProcessController(IProcessCubeClient client) { _client = client; } [HttpPost("start")] public async Task<IActionResult> StartProcess([FromBody] OrderData orderData) { try { var result = await _client.StartProcessAsync("OrderProcess", orderData); return Ok(new { Success = true, ProcessInstanceId = result.ProcessInstanceId }); } catch (Exception ex) { return StatusCode(500, new { Error = ex.Message }); } } }

Custom Serialization

Anpassen der JSON-Serialisierung

using System.Text.Json; using System.Text.Json.Serialization; var serializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, Converters = { new JsonStringEnumConverter() } }; var client = new ProcessCubeClient( "http://localhost:8000", serializerOptions: serializerOptions );

Custom HTTP Client

var httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; var client = new ProcessCubeClient( "http://localhost:8000", httpClient: httpClient );

Best Practices

Error Handling

using ProcessCube.Client.Exceptions; try { await client.StartProcessAsync("NonExistentProcess"); } catch (ProcessNotFoundException ex) { Console.WriteLine($"Process does not exist: {ex.ProcessKey}"); } catch (ProcessCubeException ex) { Console.WriteLine($"Engine error: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"Unknown error: {ex}"); }

Using Pattern

using (var client = new ProcessCubeClient("http://localhost:8000")) { var result = await client.StartProcessAsync("MyProcess"); Console.WriteLine($"Process started: {result.ProcessInstanceId}"); } // Client wird automatisch disposed

Configuration

// appsettings.json { "ProcessCube": { "EngineUrl": "http://localhost:8000", "ClientId": "my-service", "ClientSecret": "secret-key", "AuthorityUrl": "http://localhost:11235" } }
// In Program.cs oder Startup.cs services.AddProcessCubeClient(options => { Configuration.GetSection("ProcessCube").Bind(options); });

Framework-Integrationen

Windows Service

using Microsoft.Extensions.Hosting; public class ProcessWorkerService : BackgroundService { private readonly IProcessCubeClient _client; private readonly ILogger<ProcessWorkerService> _logger; public ProcessWorkerService( IProcessCubeClient client, ILogger<ProcessWorkerService> logger) { _client = client; _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { // External Tasks abrufen und verarbeiten var tasks = await _client.FetchAndLockExternalTasksAsync( "ProcessOrders", "worker-1", 5 ); foreach (var task in tasks) { await ProcessTaskAsync(task); } } catch (Exception ex) { _logger.LogError(ex, "Error processing tasks"); } await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); } } }

Blazor WebAssembly

// In Program.cs builder.Services.AddScoped<IProcessCubeClient>(sp => new ProcessCubeClient("http://localhost:8000") ); // In einer Blazor-Komponente @inject IProcessCubeClient ProcessClient @code { private List<ProcessModel> processes = new(); protected override async Task OnInitializedAsync() { processes = await ProcessClient.GetProcessesAsync(); } }

Console Application

using ProcessCube.Client; class Program { static async Task Main(string[] args) { var client = new ProcessCubeClient("http://localhost:8000"); var result = await client.StartProcessAsync("MyProcess", new { input = "Hello World" }); Console.WriteLine($"Started: {result.ProcessInstanceId}"); } }

Troubleshooting

Connection Issues

Problem: Client kann keine Verbindung zur Engine herstellen

Lösungen:

  • Prüfen Sie die Engine-URL in appsettings.json
  • Stellen Sie sicher, dass die Engine läuft
  • Überprüfen Sie Firewall-Einstellungen
  • Testen Sie mit: curl http://localhost:8000/api/info

Authentication Errors

Problem: 401 Unauthorized Fehler

Lösungen:

  • Prüfen Sie ClientId und ClientSecret
  • Stellen Sie sicher, dass der Client in der Authority registriert ist
  • Überprüfen Sie die AuthorityUrl
  • Prüfen Sie erforderliche Scopes in der Authority-Konfiguration

Serialization Issues

Problem: JSON-Serialisierungsfehler

Lösungen:

  • Verwenden Sie System.Text.Json (empfohlen) oder Newtonsoft.Json
  • Konfigurieren Sie JsonSerializerOptions korrekt
  • Prüfen Sie Property-Naming (camelCase vs PascalCase)

Weitere Ressourcen

Support

Bei Fragen oder Problemen:

  • GitHub Issues: Probleme melden 
  • Discussions: Community-Support auf GitHub Discussions