### Install WorkflowForge.Extensions.Observability.Performance Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Observability.Performance package to enable comprehensive performance monitoring for workflows. ```bash dotnet add package WorkflowForge.Extensions.Observability.Performance ``` -------------------------------- ### Install WorkflowForge Core and Extensions Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Install the core WorkflowForge package and optional extensions for logging, resilience, validation, and auditing using the .NET CLI. ```bash # Install the core package dotnet add package WorkflowForge # Optional: Install extensions for enhanced capabilities dotnet add package WorkflowForge.Extensions.Logging.Serilog dotnet add package WorkflowForge.Extensions.Resilience.Polly dotnet add package WorkflowForge.Extensions.Validation dotnet add package WorkflowForge.Extensions.Audit ``` -------------------------------- ### Verify WorkflowForge Installation Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Build your project using the .NET CLI to confirm that all WorkflowForge packages have been installed correctly. ```bash # Build to ensure everything is installed correctly dotnet build ``` -------------------------------- ### Add WorkflowForge Package Source: https://animatlabs.com/workflow-forge Install the WorkflowForge NuGet package to begin using the framework. ```bash dotnet add package WorkflowForge ``` -------------------------------- ### Execute Workflow with Smith Source: https://animatlabs.com/workflow-forge/reference/api-reference Example demonstrating how to create a `WorkflowSmith`, create a foundry associated with a workflow, and then execute the workflow using the smith. ```csharp using var smith = WorkflowForge.CreateSmith(); using var foundry = smith.CreateFoundryFor(workflow); await smith.ForgeAsync(workflow, foundry); ``` -------------------------------- ### Install WorkflowForge.Extensions.Persistence Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Persistence package to your project to enable core workflow state persistence. ```bash dotnet add package WorkflowForge.Extensions.Persistence ``` -------------------------------- ### Install Workflow Forge Testing Package Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Install the WorkflowForge.Testing package using the .NET CLI to enable unit testing of operations. ```bash dotnet add package WorkflowForge.Testing ``` -------------------------------- ### Unit Test Example: Executing Multiple Operations Source: https://animatlabs.com/workflow-forge/reference/api-reference Example demonstrating how to use FakeWorkflowFoundry to test the execution of multiple operations in sequence. It shows how to add operations to the foundry and then assert that all added operations were executed. ```csharp [Fact] public async Task Workflow_Should_ExecuteAllOperations() { // Arrange var foundry = new FakeWorkflowFoundry(); foundry.AddOperation(new StepOneOperation()); foundry.AddOperation(new StepTwoOperation()); // Act await foundry.ForgeAsync(); // Assert Assert.Equal(2, foundry.ExecutedOperations.Count); } ``` -------------------------------- ### TimingMiddleware Implementation Example Source: https://animatlabs.com/workflow-forge/reference/api-reference An example implementation of the IWorkflowOperationMiddleware interface that measures and logs the execution time of an operation. This demonstrates how to wrap the call to `next` to perform actions before and after the operation or subsequent middleware. ```csharp public class TimingMiddleware : IWorkflowOperationMiddleware { public async Task ExecuteAsync( IWorkflowOperation operation, IWorkflowFoundry foundry, object? inputData, Func> next, CancellationToken cancellationToken) { var sw = Stopwatch.StartNew(); try { return await next(cancellationToken); } finally { sw.Stop(); _logger.LogInformation("Operation {Op} took {Ms}ms", operation.Name, sw.ElapsedMilliseconds); } } } ``` -------------------------------- ### Unit Test Example: Setting a Property Source: https://animatlabs.com/workflow-forge/reference/api-reference Example of using FakeWorkflowFoundry in a unit test to verify that an operation correctly sets a property on the foundry. This demonstrates how to arrange the test, act by executing the operation, and assert the expected outcome. ```csharp [Fact] public async Task MyOperation_Should_SetProperty() { // Arrange var foundry = new FakeWorkflowFoundry(); var operation = new MyCustomOperation(); // Act await operation.ForgeAsync("input", foundry, CancellationToken.None); // Assert Assert.True(foundry.Properties.ContainsKey("myKey")); Assert.Equal("expectedValue", foundry.Properties["myKey"]); } ``` -------------------------------- ### Handle Operation Lifecycle Events Source: https://animatlabs.com/workflow-forge/reference/api-reference Example of subscribing to operation lifecycle events to log when an individual operation starts and completes. ```csharp foundry.OperationStarted += (s, e) => Console.WriteLine($"Operation {e.Operation.Name} started"); foundry.OperationCompleted += (s, e) => Console.WriteLine($"Operation {e.Operation.Name} completed"); ``` -------------------------------- ### Install WorkflowForge OpenTelemetry Package Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Observability.OpenTelemetry package to your project for distributed tracing and telemetry. ```bash dotnet add package WorkflowForge.Extensions.Observability.OpenTelemetry ``` -------------------------------- ### Dependency Inversion Principle Example Source: https://animatlabs.com/workflow-forge/architecture/overview Illustrates the Dependency Inversion Principle by defining core abstractions and then providing concrete implementations. ```csharp // Abstractions define contracts public interface IWorkflowFoundry { } public interface IWorkflowOperation { } // Implementations fulfill contracts internal sealed class WorkflowFoundry : IWorkflowFoundry { } public sealed class DelegateWorkflowOperation : IWorkflowOperation { } ``` -------------------------------- ### Install WorkflowForge.Extensions.Persistence.Recovery Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Persistence.Recovery package to enable automatic workflow resumption from saved states. ```bash dotnet add package WorkflowForge.Extensions.Persistence.Recovery ``` -------------------------------- ### ForEachWorkflowOperation Examples Source: https://animatlabs.com/workflow-forge/reference/api-reference Illustrates creating ForEachWorkflowOperations using factory methods for shared input with concurrency limits and throttled split input execution. ```csharp // Execute multiple operations in parallel with shared input var forEachOp = ForEachWorkflowOperation.CreateSharedInput( new IWorkflowOperation[] { new ProcessA(), new ProcessB(), new ProcessC() }, maxConcurrency: 4, name: "ProcessAll"); // Throttled execution with 2 concurrent operations max var throttledOp = ForEachWorkflowOperation.CreateSplitInput( operations, maxConcurrency: 2); ``` -------------------------------- ### Install WorkflowForge Audit Extension Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Audit package to your project using the .NET CLI. ```bash dotnet add package WorkflowForge.Extensions.Audit ``` -------------------------------- ### Optimal Middleware Ordering Example Source: https://animatlabs.com/workflow-forge/architecture/middleware-pipeline Illustrates the recommended order for adding middleware to ensure proper wrapping and error handling. Observability should be outermost, followed by resilience, and then business logic. ```csharp // Step 1: Observability - measures total execution time foundry.EnablePerformanceMonitoring(); // Step 2: Resilience - retries failed operations foundry.UsePollyRetry(maxRetryAttempts: 3); // Step 3: Business logic - validates and audits foundry.UseValidation(f => f.GetPropertyOrDefault("Order")); foundry.UseAudit(auditProvider); ``` -------------------------------- ### Create and Forge a Simple Workflow Source: https://animatlabs.com/workflow-forge This example demonstrates how to create a simple workflow named 'HelloWorld' with a single operation that logs a message, and then forge (execute) it using a WorkflowSmith. ```APIDOC ## Create and Forge a Simple Workflow ### Description This example demonstrates how to create a simple workflow named 'HelloWorld' with a single operation that logs a message, and then forge (execute) it using a WorkflowSmith. ### Code ```csharp using WorkflowForge; var workflow = WorkflowForge.CreateWorkflow("HelloWorld") .AddOperation("SayHello", async (foundry, ct) => { foundry.Logger.LogInformation("Hello, WorkflowForge!"); }) .Build(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` ``` -------------------------------- ### Focused Operations Example Source: https://animatlabs.com/workflow-forge/core/operations Demonstrates the recommended practice of creating focused operations, each performing a single, well-defined task within the workflow. ```csharp // Good: Focused operations .AddOperation("ValidateOrder", ValidateAsync) .AddOperation("ReserveInventory", ReserveAsync) .AddOperation("ProcessPayment", ProcessPaymentAsync) // Bad: God operation .AddOperation("ProcessEverything", async (foundry, ct) => { // Validation, inventory, payment all mixed together }) ``` -------------------------------- ### Install WorkflowForge.Extensions.Validation Source: https://animatlabs.com/workflow-forge/extensions Command to add the Validation extension package to your .NET project. ```bash dotnet add package WorkflowForge.Extensions.Validation ``` -------------------------------- ### LoggingOperation Example Source: https://animatlabs.com/workflow-forge/reference/api-reference Shows how to include a LoggingOperation in a workflow to output a message at a specific log level during execution. ```csharp var workflow = WorkflowForge.CreateWorkflow("LoggingWorkflow") .AddOperation(new LoggingOperation("Starting workflow")) .Build(); ``` -------------------------------- ### Enable OpenTelemetry for Observability Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Integrate OpenTelemetry to gain distributed tracing and metrics capabilities. This example creates a foundry and enables OpenTelemetry with service name and version. ```csharp using WorkflowForge.Extensions.Observability.OpenTelemetry; var foundry = WorkflowForge.CreateFoundry("ProcessOrder"); foundry.EnableOpenTelemetry(new WorkflowForgeOpenTelemetryOptions { ServiceName = "OrderService", ServiceVersion = "1.0.0" }); ``` -------------------------------- ### Workflow Middleware Implementation Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Demonstrates implementing workflow-level middleware using the `IWorkflowMiddleware` interface. This example shows how to add timing and audit middleware to the workflow smith for execution. ```csharp public sealed class WorkflowTimingMiddleware : IWorkflowMiddleware { public async Task ExecuteAsync( IWorkflow workflow, IWorkflowFoundry foundry, Func next, CancellationToken cancellationToken) { var start = DateTimeOffset.UtcNow; foundry.Logger.LogInformation("[WorkflowTiming] Starting {WorkflowName}", workflow.Name); await next().ConfigureAwait(false); var duration = DateTimeOffset.UtcNow - start; foundry.Logger.LogInformation("[WorkflowTiming] Completed in {DurationMs}ms", duration.TotalMilliseconds.ToString("F0")); } } var smith = WorkflowForge.CreateSmith(logger); smith.AddWorkflowMiddleware(new WorkflowTimingMiddleware()); smith.AddWorkflowMiddleware(new WorkflowAuditMiddleware()); await smith.ForgeAsync(workflow); ``` -------------------------------- ### DelayOperation Example Source: https://animatlabs.com/workflow-forge/reference/api-reference Demonstrates how to add a DelayOperation to a workflow, pausing execution for a specified duration. ```csharp var workflow = WorkflowForge.CreateWorkflow("DelayedWorkflow") .AddOperation(new DelayOperation(TimeSpan.FromSeconds(2))) .Build(); ``` -------------------------------- ### WorkflowForge Factory Methods Source: https://animatlabs.com/workflow-forge/architecture/overview Provides examples of static factory methods exposed by the `WorkflowForge` class for creating workflows, foundries, and smiths. ```csharp public static class WorkflowForge { // Workflow creation public static WorkflowBuilder CreateWorkflow(string? workflowName = null, IServiceProvider? serviceProvider = null) // Foundry creation public static IWorkflowFoundry CreateFoundry( string workflowName, IWorkflowForgeLogger? logger = null, IDictionary? initialProperties = null, WorkflowForgeOptions? options = null) // Smith creation public static IWorkflowSmith CreateSmith( IWorkflowForgeLogger? logger = null, IServiceProvider? serviceProvider = null, WorkflowForgeOptions? options = null) } ``` -------------------------------- ### Create Workflow Builder Source: https://animatlabs.com/workflow-forge/reference/api-reference Use this method to start building a new workflow. You can optionally provide a name and a service provider for dependency injection. ```csharp var workflow = WorkflowForge.CreateWorkflow("OrderProcessing") .AddOperation(new ValidateOperation()) .Build(); ``` -------------------------------- ### Create and Execute Simple Workflow Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Demonstrates the simplest way to create a workflow with inline operations and execute it using WorkflowSmith. Suitable for basic logging and initial workflow setup. ```csharp var workflow = WorkflowForge.CreateWorkflow("HelloWorld") .AddOperation("SayHello", (foundry, ct) => { foundry.Logger.LogInformation("Hello, World!"); return Task.CompletedTask; }) .Build(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### TimeSensitiveOperation Example Source: https://animatlabs.com/workflow-forge/reference/api-reference Demonstrates how to use ISystemTimeProvider within a workflow operation to access the current UTC time for time-dependent logic. ```csharp public class TimeSensitiveOperation : WorkflowOperationBase { private readonly ISystemTimeProvider _timeProvider; public TimeSensitiveOperation(ISystemTimeProvider timeProvider) { _timeProvider = timeProvider; } protected override async Task ForgeAsyncCore( object? inputData, IWorkflowFoundry foundry, CancellationToken cancellationToken) { var now = _timeProvider.UtcNow; // Time-dependent logic return inputData; } } ``` -------------------------------- ### Implement and Configure File Audit Provider Source: https://animatlabs.com/workflow-forge/core/configuration Provides an example of implementing a custom `IAuditProvider` for file-based logging and configuring the Audit Logger with this provider. This extension has zero external dependencies. ```csharp using WorkflowForge.Extensions.Audit; // Implement audit provider public class FileAuditProvider : IAuditProvider { private readonly string _logPath; private readonly SemaphoreSlim _writeLock = new(1, 1); public FileAuditProvider(string logPath) { _logPath = logPath; } public async Task WriteAuditEntryAsync( AuditEntry entry, CancellationToken cancellationToken = default) { await _writeLock.WaitAsync(cancellationToken); try { var json = JsonSerializer.Serialize(entry); await File.AppendAllTextAsync(_logPath, json + Environment.NewLine, cancellationToken); } finally { _writeLock.Release(); } } public Task FlushAsync(CancellationToken cancellationToken = default) { return Task.CompletedTask; } } // Configure audit logging var auditProvider = new FileAuditProvider("audit.log"); var auditLogger = new AuditLogger( auditProvider, userId: "user@example.com", sessionId: Guid.NewGuid().ToString(), timeProvider: new SystemTimeProvider()); // Subscribe to events smith.WorkflowStarted += async (s, e) => await auditLogger.LogWorkflowStartedAsync(e); smith.WorkflowCompleted += async (s, e) => await auditLogger.LogWorkflowCompletedAsync(e); foundry.OperationCompleted += async (s, e) => await auditLogger.LogOperationCompletedAsync(e); await smith.ForgeAsync(workflow, foundry); ``` -------------------------------- ### AuditedOperation Example with Lifecycle Hooks Source: https://animatlabs.com/workflow-forge/reference/api-reference Demonstrates how to extend `WorkflowOperationBase` and implement lifecycle hooks (`OnBeforeExecuteAsync`, `OnAfterExecuteAsync`) and the core logic (`ForgeAsyncCore`) for custom operation behavior. ```csharp public class AuditedOperation : WorkflowOperationBase { public override string Name => "AuditedOperation"; protected override Task OnBeforeExecuteAsync(object? inputData, IWorkflowFoundry foundry, CancellationToken ct) { foundry.Logger.LogInformation("Starting operation with input: {Input}", inputData); return Task.CompletedTask; } protected override async Task ForgeAsyncCore(object? inputData, IWorkflowFoundry foundry, CancellationToken ct) { // Your operation logic here return await ProcessAsync(inputData, ct); } protected override Task OnAfterExecuteAsync(object? inputData, object? outputData, IWorkflowFoundry foundry, CancellationToken ct) { foundry.Logger.LogInformation("Completed operation with result: {Output}", outputData); return Task.CompletedTask; } } ``` -------------------------------- ### Handle Compensation Lifecycle Events Source: https://animatlabs.com/workflow-forge/reference/api-reference Example of subscribing to compensation events to log when compensation is triggered and when rollback operations begin. ```csharp smith.CompensationTriggered += (s, e) => Console.WriteLine($"Compensating: {e.Reason} (failed: {e.FailedOperationName})"); smith.OperationRestoreStarted += (s, e) => Console.WriteLine($"Rolling back {e.Operation.Name}"); ``` -------------------------------- ### Debugging Middleware Execution Order with Logging Source: https://animatlabs.com/workflow-forge/architecture/middleware-pipeline Provides an example of how to use logging middleware to trace the execution flow of the middleware pipeline. This helps in understanding the order of operations and debugging. ```csharp foundry.AddMiddleware(new LoggingMiddleware("OUTER")); foundry.AddMiddleware(new LoggingMiddleware("MIDDLE")); foundry.AddMiddleware(new LoggingMiddleware("INNER")); // Output will show: // OUTER: Before // MIDDLE: Before // INNER: Before // [Operation executes] // INNER: After // MIDDLE: After // OUTER: After ``` -------------------------------- ### Enable and Use OpenTelemetry with WorkflowForge Source: https://animatlabs.com/workflow-forge/extensions Enable OpenTelemetry for a foundry instance to get distributed tracing and telemetry. Use StartActivity to create custom spans and SetTag to add metadata. ```csharp using WorkflowForge.Extensions.Observability.OpenTelemetry; var foundry = WorkflowForge.CreateFoundry("ProcessOrder"); foundry.EnableOpenTelemetry(new WorkflowForgeOpenTelemetryOptions { ServiceName = "OrderService", ServiceVersion = "1.0.0" }); // Create custom spans using var activity = foundry.StartActivity("ProcessOrder") .SetTag("order.id", order.Id) .SetTag("customer.id", order.CustomerId); // Execute with tracing foundry.SetProperty("Order", order); await smith.ForgeAsync(workflow, foundry); // Add custom events using var activity = foundry.StartActivity("PaymentProcessed"); activity?.SetTag("amount", order.Amount.ToString()); ``` -------------------------------- ### Dictionary Context Data Flow Example Source: https://animatlabs.com/workflow-forge/architecture/overview Demonstrates using a dictionary context for passing data between workflow operations. Use this pattern for dynamic payloads or when operations evolve frequently. ```csharp var workflow = WorkflowForge.CreateWorkflow() .WithName("OrderProcessing") .AddOperation("ValidateOrder", async (foundry, ct) => { // Store data in foundry properties (typed helpers) foundry.SetProperty("OrderId", orderId); foundry.SetProperty("Customer", customer); foundry.SetProperty("TotalAmount", 100.50m); }) .AddOperation("ProcessPayment", async (foundry, ct) => { // Retrieve data from foundry properties var orderId = foundry.GetPropertyOrDefault("OrderId"); var amount = foundry.GetPropertyOrDefault("TotalAmount"); // Process payment... }) .Build(); ``` -------------------------------- ### Implement a Custom Database Audit Provider Source: https://animatlabs.com/workflow-forge/extensions Create a custom audit provider by implementing the IAuditProvider interface to store audit entries in a database. This example shows how to integrate with a DbContext. ```csharp public class DatabaseAuditProvider : IAuditProvider { private readonly DbContext _context; public async Task WriteAuditEntryAsync(AuditEntry entry) { _context.AuditLog.Add(entry); await _context.SaveChangesAsync(); } public async Task FlushAsync() { await _context.SaveChangesAsync(); } } // Use custom provider var auditProvider = new DatabaseAuditProvider(dbContext); foundry.UseAudit(auditProvider); ``` -------------------------------- ### Create and Execute a Simple Workflow Source: https://animatlabs.com/workflow-forge Demonstrates creating a basic workflow named 'HelloWorld' with a single logging operation and executing it using a smith. ```csharp using WorkflowForge; var workflow = WorkflowForge.CreateWorkflow("HelloWorld") .AddOperation("SayHello", async (foundry, ct) => { foundry.Logger.LogInformation("Hello, WorkflowForge!"); }) .Build(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### Store and Retrieve Data in Foundry Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Examples of using the foundry's property bag to store and retrieve data using string keys. Use `SetProperty` to store and `GetPropertyOrDefault` to retrieve. ```csharp // Store data foundry.SetProperty("Key", value); // Retrieve data var value = foundry.GetPropertyOrDefault("Key"); // Retrieve with default var value = foundry.GetPropertyOrDefault("Key", defaultValue); ``` -------------------------------- ### Handle Workflow Lifecycle Events Source: https://animatlabs.com/workflow-forge/reference/api-reference Example of subscribing to workflow lifecycle events to log workflow start and completion details, including execution duration. ```csharp smith.WorkflowStarted += (s, e) => Console.WriteLine($"Started: {e.Foundry.CurrentWorkflow?.Name}"); smith.WorkflowCompleted += (s, e) => Console.WriteLine($"Completed in {e.Duration.TotalMilliseconds}ms"); ``` -------------------------------- ### Resume Workflow with Recovery Middleware Source: https://animatlabs.com/workflow-forge/extensions Configure and use the recovery middleware to automatically resume interrupted workflows. This example shows how to set retry attempts and enable exponential backoff for recovery. ```csharp using WorkflowForge.Extensions.Persistence; using WorkflowForge.Extensions.Persistence.Recovery; var provider = new MyStorageProvider(); // Resume workflow from last checkpoint using var foundry = WorkflowForge.CreateFoundry("RecoveredWorkflow"); foundry.UsePersistence(provider, options); var smith = WorkflowForge.CreateSmith(); await smith.ForgeWithRecoveryAsync( workflow, foundry, provider, foundryKey, workflowKey, new RecoveryMiddlewareOptions { MaxRetryAttempts = 3, UseExponentialBackoff = true }); ``` -------------------------------- ### Clone and Run Samples Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Commands to clone the WorkflowForge repository and run a basic console sample application. ```bash # Clone the repository git clone https://github.com/animatlabs/workflow-forge.git cd workflow-forge # Run the samples cd src/samples/WorkflowForge.Samples.BasicConsole dotnet run ``` -------------------------------- ### OperationRestoreStartedEventArgs Definition Source: https://animatlabs.com/workflow-forge/core/events Defines the arguments for an operation restore start event. Includes the operation and start time. ```csharp public class OperationRestoreStartedEventArgs : BaseWorkflowForgeEventArgs { public IWorkflowOperation Operation { get; } public DateTimeOffset StartedAt { get; } } ``` -------------------------------- ### ConditionalWorkflowOperation Example Source: https://animatlabs.com/workflow-forge/reference/api-reference An example of creating a ConditionalWorkflowOperation using a lambda expression for the condition and specifying operations for true and false outcomes. ```csharp var conditionalOp = new ConditionalWorkflowOperation( condition: (input, f) => f.GetPropertyOrDefault("Amount") > 100, trueOperation: new HighValueOperation(), falseOperation: new StandardOperation()); ``` -------------------------------- ### Registering WorkflowForge Configuration in Startup Source: https://animatlabs.com/workflow-forge/core/configuration Demonstrates how to register WorkflowForge configuration and its extensions using the Options pattern in ASP.NET Core applications. This involves building the configuration and adding services for core settings and specific extensions. ```csharp using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using WorkflowForge.Options; using WorkflowForge.Extensions.Resilience.Polly; using WorkflowForge.Extensions.Resilience.Polly.Options; using WorkflowForge.Extensions.Validation; using WorkflowForge.Extensions.Audit; using WorkflowForge.Extensions.Persistence; // Build configuration var configuration = new ConfigurationBuilder() .SetBasePath(AppContext.BaseDirectory) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{environment}.json", optional: true) .AddEnvironmentVariables() .Build(); // Register configuration with Options pattern var services = new ServiceCollection(); services.AddSingleton(configuration); // Core WorkflowForge settings services.Configure( configuration.GetSection(WorkflowForgeOptions.DefaultSectionName)); // Extension settings using extension methods services.AddWorkflowForgePolly(configuration); services.AddValidationConfiguration(configuration); services.AddAuditConfiguration(configuration); services.AddPersistenceConfiguration(configuration); var serviceProvider = services.BuildServiceProvider(); ``` -------------------------------- ### Create a New Console Application Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Use the .NET CLI to create a new console application and navigate into its directory. This is the initial step for setting up your WorkflowForge project. ```bash # Create a new console application dotnet new console -n MyWorkflowApp cd MyWorkflowApp ``` -------------------------------- ### Build and Execute a Workflow Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Demonstrates building a complete order processing workflow with operations for validation, payment, and fulfillment, then executing it using a foundry and smith with a console logger. ```csharp // Program.cs using WorkflowForge; using WorkflowForge.Loggers; // Create an order var order = new Order { Id = Guid.NewGuid().ToString("N"), CustomerId = "CUST-123", Amount = 99.99m, Items = new List { "Product A", "Product B" } }; Console.WriteLine($"Processing order {order.Id}... "); // Build the workflow var workflow = WorkflowForge.CreateWorkflow("ProcessOrder") .WithDescription("Complete order processing workflow") .WithVersion("2.1.1") .AddOperation(new ValidateOrderOperation()) .AddOperation(new ProcessPaymentOperation()) .AddOperation(new FulfillOrderOperation()) .Build(); // Create a foundry with the order data var foundry = WorkflowForge.CreateFoundry( "ProcessOrder", initialProperties: new Dictionary { ["Order"] = order }); // Create a smith (orchestrator) with console logger using var smith = WorkflowForge.CreateSmith(new ConsoleLogger()); try { // Execute the workflow await smith.ForgeAsync(workflow, foundry); Console.WriteLine($"\nOrder processed successfully!"); Console.WriteLine($"Final status: {order.Status}"); var paymentResult = foundry.GetPropertyOrDefault("PaymentResult"); if (paymentResult != null) { Console.WriteLine($"Transaction ID: {paymentResult.TransactionId}"); } } catch (Exception ex) { Console.WriteLine($"\nWorkflow failed: {ex.Message}"); } ``` -------------------------------- ### OperationStartedEventArgs Definition Source: https://animatlabs.com/workflow-forge/core/events Defines the arguments for an operation start event. Includes the operation and its input data. ```csharp public class OperationStartedEventArgs : BaseWorkflowForgeEventArgs { public IWorkflowOperation Operation { get; } public object? InputData { get; } } ``` -------------------------------- ### Basic Workflow Creation Source: https://animatlabs.com/workflow-forge/core/configuration Creates a simple workflow with default settings and executes it. ```csharp using WorkflowForge; // Simple workflow with defaults var workflow = WorkflowForge.CreateWorkflow("SimpleWorkflow") .AddOperation(new CalculateTotal()) .AddOperation(new SendNotification()) .Build(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### Comprehensive Integration Sample Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Demonstrates combining multiple Workflow Forge extensions for complex, production-grade workflows. This sample showcases best practices for real-world scenarios. ```csharp foundry.EnablePerformanceMonitoring(); foundry.UsePollyRetry(maxRetryAttempts: 3); foundry.UseValidation(f => f.GetPropertyOrDefault("Order")); foundry.UseAudit(auditProvider); foundry.UsePersistence(persistenceProvider); foundry.UseTiming(); // Complex workflow with all features enabled ``` -------------------------------- ### Run the Application Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Command to execute the .NET application from the terminal. ```bash dotnet run ``` -------------------------------- ### Define Order Model with DataAnnotations Source: https://animatlabs.com/workflow-forge/extensions Example of defining a model class with DataAnnotations for validation rules. ```csharp using System.ComponentModel.DataAnnotations; using WorkflowForge.Extensions.Validation; // Define model with DataAnnotations public class Order { [Required] public string CustomerId { get; set; } = string.Empty; [Range(0.01, double.MaxValue)] public decimal Amount { get; set; } } ``` -------------------------------- ### Configuring Workflow Forge with Options Pattern Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Demonstrates how to configure Workflow Forge using the options pattern, including binding settings from appsettings.json. ```csharp services.Configure( Configuration.GetSection(WorkflowForgeOptions.DefaultSectionName) ); var config = serviceProvider.GetRequiredService>(); ``` -------------------------------- ### WorkflowForge Audit Configuration Source: https://animatlabs.com/workflow-forge/extensions Example JSON configuration for enabling and customizing audit logging behavior in WorkflowForge. ```json { "WorkflowForge": { "Audit": { "Enabled": true, "IncludeMetadata": true, "DefaultInitiatedBy": "system" } } } ``` -------------------------------- ### Workflow Event Arguments Source: https://animatlabs.com/workflow-forge/core/events Specific event argument classes for workflow-level events, including start, completion, and failure details. ```csharp public class WorkflowStartedEventArgs : BaseWorkflowForgeEventArgs { public DateTimeOffset StartedAt { get; } } ``` ```csharp public class WorkflowCompletedEventArgs : BaseWorkflowForgeEventArgs { public DateTimeOffset CompletedAt { get; } public IReadOnlyDictionary FinalProperties { get; } public TimeSpan Duration { get; } } ``` ```csharp public class WorkflowFailedEventArgs : BaseWorkflowForgeEventArgs { public DateTimeOffset FailedAt { get; } public Exception? Exception { get; } public string FailedOperationName { get; } public TimeSpan Duration { get; } } ``` -------------------------------- ### Install WorkflowForge Health Checks Package Source: https://animatlabs.com/workflow-forge/extensions Add the WorkflowForge.Extensions.Observability.HealthChecks package to your project to enable system health monitoring and diagnostics. ```bash dotnet add package WorkflowForge.Extensions.Observability.HealthChecks ``` -------------------------------- ### Integrate Events with Monitoring Systems Source: https://animatlabs.com/workflow-forge/core/events Examples of integrating Workflow Forge events with Application Insights for telemetry and Prometheus for metrics. ```csharp // Integrate with Application Insights smith.WorkflowCompleted += (s, e) => { _telemetryClient.TrackEvent("WorkflowCompleted", new Dictionary { ["WorkflowName"] = e.Foundry.CurrentWorkflow?.Name ?? "", ["Duration"] = e.Duration.TotalMilliseconds.ToString(), ["PropertyCount"] = e.FinalProperties.Count.ToString() }); }; // Integrate with Prometheus foundry.OperationCompleted += (s, e) => { _operationDurationHistogram .WithLabels(e.Foundry.CurrentWorkflow?.Name ?? "", e.Operation.Name) .Observe(e.Duration.TotalSeconds); }; ``` -------------------------------- ### Create Foundry for Production Environment Source: https://animatlabs.com/workflow-forge/core/configuration Configures a Workflow Foundry instance with information-level logging for production. Does not include timing middleware by default. ```csharp public static class ProductionConfiguration { public static IWorkflowFoundry CreateFoundry(string name) { var logger = SerilogLoggerFactory.CreateLogger(new SerilogLoggerOptions { MinimumLevel = "Information", EnableConsoleSink = true }); return WorkflowForge.CreateFoundry(name, logger); } } ``` -------------------------------- ### Run Competitive Benchmarks Source: https://animatlabs.com/workflow-forge/performance/performance Execute competitive benchmarks to compare WorkflowForge against other workflow engines. Navigate to the comparative benchmark directory and run the command. ```bash cd src/benchmarks/WorkflowForge.Benchmarks.Comparative dotnet run -c Release ``` -------------------------------- ### SRP Adherence Example Source: https://animatlabs.com/workflow-forge/architecture/overview Shows the WorkflowForge design adhering to SRP by separating concerns into distinct interfaces for different event types. ```csharp // Three focused interfaces public interface IWorkflowLifecycleEvents { /* workflow events */ } public interface IOperationLifecycleEvents { /* operation events */ } public interface ICompensationLifecycleEvents { /* compensation events */ } ``` -------------------------------- ### Store and Retrieve Data using Dictionary Source: https://animatlabs.com/workflow-forge/core/operations Demonstrates how to use a dictionary (foundry.Properties) to store and retrieve data between workflow operations. This provides flexibility for evolving data shapes and loose coupling. ```csharp // Operation 1: Store data foundry.Properties["CustomerId"] = customerId; foundry.Properties["OrderDate"] = DateTime.UtcNow; foundry.Properties["Items"] = orderItems; // Operation 2: Retrieve data var customerId = (string)foundry.Properties["CustomerId"]; var orderDate = (DateTime)foundry.Properties["OrderDate"]; var items = foundry.Properties["Items"] as List; ``` -------------------------------- ### SRP Violation Example Source: https://animatlabs.com/workflow-forge/architecture/overview Demonstrates an anti-pattern where a single interface handles multiple unrelated events, violating the Single Responsibility Principle. ```csharp // One interface doing everything - violates SRP public interface IWorkflowEvents { event WorkflowStarted; event OperationStarted; event CompensationStarted; // ... all events mixed together } ``` -------------------------------- ### Create Foundry for Development Environment Source: https://animatlabs.com/workflow-forge/core/configuration Configures a Workflow Foundry instance with logging enabled for development. Includes timing middleware for performance monitoring. ```csharp public static class DevelopmentConfiguration { public static IWorkflowFoundry CreateFoundry(string name) { var logger = SerilogLoggerFactory.CreateLogger(new SerilogLoggerOptions { MinimumLevel = "Debug", EnableConsoleSink = true }); var foundry = WorkflowForge.CreateFoundry(name, logger); foundry.UseTiming(); return foundry; } } ``` -------------------------------- ### Monitoring Workflow Operations Source: https://animatlabs.com/workflow-forge/core/events Subscribes to operation-specific events (start, complete, fail) using a 'Foundry' instance. Useful for detailed operation monitoring. ```csharp using var foundry = WorkflowForge.CreateFoundry("MonitoredWorkflow"); // Subscribe to operation events foundry.OperationStarted += (sender, e) => { Console.WriteLine($"Operation {e.Operation.Name} started"); }; foundry.OperationCompleted += (sender, e) => { Console.WriteLine($"Operation {e.Operation.Name} completed in {e.Duration.TotalMilliseconds}ms"); }; foundry.OperationFailed += (sender, e) => { Console.WriteLine($"Operation {e.Operation.Name} failed: {e.Exception?.Message}"); }; // Execute workflow with foundry using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow, foundry); ``` -------------------------------- ### Run Internal Benchmarks Source: https://animatlabs.com/workflow-forge/performance/performance Execute internal benchmarks to measure WorkflowForge performance. Navigate to the benchmark directory and run the command. ```bash cd src/benchmarks/WorkflowForge.Benchmarks dotnet run -c Release ``` -------------------------------- ### Basic Workflow Event Subscription Source: https://animatlabs.com/workflow-forge/core/events Subscribes to basic workflow events like start, completion, and failure. Requires creating a 'Smith' instance. ```csharp using var smith = WorkflowForge.CreateSmith(); // Subscribe to workflow events smith.WorkflowStarted += (sender, e) => { Console.WriteLine($"Workflow {e.Foundry.CurrentWorkflow?.Name} started at {e.Timestamp}"); }; smith.WorkflowCompleted += (sender, e) => { Console.WriteLine($"Workflow completed in {e.Duration.TotalMilliseconds}ms"); }; smith.WorkflowFailed += (sender, e) => { Console.WriteLine($"Workflow failed: {e.Exception?.Message}"); }; // Execute workflow await smith.ForgeAsync(workflow); ``` -------------------------------- ### Environment-Specific Workflow Forge Configuration Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Provides examples of creating Workflow Forge foundries with different configuration profiles for production and high-throughput environments. ```csharp var productionOptions = new WorkflowForgeOptions { Enabled = true, ContinueOnError = false, FailFastCompensation = false, ThrowOnCompensationError = true, EnableOutputChaining = true }; var highThroughputOptions = new WorkflowForgeOptions { Enabled = true, ContinueOnError = true, FailFastCompensation = false, ThrowOnCompensationError = false, EnableOutputChaining = true }; var productionFoundry = WorkflowForge.CreateFoundry("Workflow", options: productionOptions); var highPerfFoundry = WorkflowForge.CreateFoundry("Workflow", options: highThroughputOptions); ``` -------------------------------- ### Unit Test Workflow Operations Source: https://animatlabs.com/workflow-forge/getting-started/getting-started Use FakeWorkflowFoundry and Xunit to unit test individual operations in isolation. This example demonstrates testing a validation operation. ```csharp using WorkflowForge.Testing; using Xunit; public class MyOperationTests { [Fact] public async Task Operation_Should_SetProperty() { // Arrange var foundry = new FakeWorkflowFoundry(); var operation = new ValidateOrderOperation(); foundry.Properties["Order"] = new Order { Id = "123", Amount = 99.99m }; // Act await operation.ForgeAsync(null, foundry, CancellationToken.None); // Assert - no exception means validation passed } } ``` -------------------------------- ### Implement Timing Middleware in C# Source: https://animatlabs.com/workflow-forge/architecture/overview Example implementation of IWorkflowOperationMiddleware that measures and logs the execution time of an operation. It wraps the call to the next middleware or the operation itself. ```csharp public class TimingMiddleware : IWorkflowOperationMiddleware { public async Task ExecuteAsync( IWorkflowOperation operation, IWorkflowFoundry foundry, object? inputData, Func> next, CancellationToken cancellationToken) { var sw = Stopwatch.StartNew(); try { return await next(cancellationToken); // Call next middleware or operation } finally { sw.Stop(); foundry.Logger.LogInformation( "Operation {Name} took {Ms}ms", operation.Name, sw.ElapsedMilliseconds); } } } ``` -------------------------------- ### Create Reusable Event Handlers Source: https://animatlabs.com/workflow-forge/core/events Factory methods to create reusable event handlers for common tasks like logging workflow start and failure events. ```csharp public static class WorkflowEventHandlers { public static EventHandler CreateStartLogger(ILogger logger) { return (sender, e) => logger.LogInformation( "Workflow {WorkflowName} started with {OperationCount} operations", e.Foundry.CurrentWorkflow?.Name, e.Foundry.CurrentWorkflow?.Operations.Count ?? 0); } public static EventHandler CreateErrorLogger(ILogger logger) { return (sender, e) => logger.LogError( e.Exception, "Workflow {WorkflowName} failed at operation {OperationName}", e.Foundry.CurrentWorkflow?.Name, e.FailedOperationName); } } // Usage smith.WorkflowStarted += WorkflowEventHandlers.CreateStartLogger(logger); smith.WorkflowFailed += WorkflowEventHandlers.CreateErrorLogger(logger); ``` -------------------------------- ### Configure and Use Polly Retry Policy Source: https://animatlabs.com/workflow-forge/core/configuration Demonstrates how to configure a Polly retry policy for HTTP request exceptions and wrap an operation with it. Ensure Polly is referenced correctly. ```csharp using WorkflowForge.Extensions.Resilience.Polly; using Polly; // Configure retry policy var retryPolicy = Policy .Handle() .WaitAndRetryAsync( retryCount: 3, sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), onRetry: (exception, timeSpan, retryCount, context) => { logger.LogWarning("Retry {RetryCount} after {Delay}ms", retryCount, timeSpan.TotalMilliseconds); }); // Wrap operation with Polly retry var resilientOp = PollyRetryOperation.WithRetryPolicy( new CallExternalApiOperation(), maxRetryAttempts: 3, baseDelay: TimeSpan.FromSeconds(1)); var workflow = WorkflowForge.CreateWorkflow("ResilientWorkflow") .AddOperation(resilientOp) .Build(); ``` -------------------------------- ### Use Configuration in Application Source: https://animatlabs.com/workflow-forge/core/configuration Inject IOptions for WorkflowForgeOptions and PollyMiddlewareOptions to access configuration values. Configuration is automatically loaded from appsettings.json. ```csharp using Microsoft.Extensions.Options; using WorkflowForge.Options; using WorkflowForge.Extensions.Resilience.Polly.Options; public class OrderWorkflowService { private readonly IOptions _workflowOptions; private readonly IOptions _pollyOptions; public OrderWorkflowService( IOptions workflowOptions, IOptions pollyOptions) { _workflowOptions = workflowOptions; _pollyOptions = pollyOptions; } public async Task ProcessOrderAsync(Order order) { // Configuration is automatically loaded from appsettings.json var settings = _workflowOptions.Value; Console.WriteLine($"MaxConcurrentWorkflows: {settings.MaxConcurrentWorkflows}"); Console.WriteLine($"ContinueOnError: {settings.ContinueOnError}"); // Create foundry and apply configuration using var foundry = WorkflowForge.CreateFoundry($"Order-{order.Id}"); // Apply Polly configuration if enabled if (_pollyOptions.Value.Enabled) { foundry.UsePollyFromSettings(_pollyOptions.Value); } foundry.SetProperty("Order", order); var workflow = BuildOrderWorkflow(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow, foundry); } } ``` -------------------------------- ### Implementing an Audit Trail for Workflow Events Source: https://animatlabs.com/workflow-forge/core/events Log significant workflow events, such as start, completion, and failure, to an audit repository. This pattern is crucial for compliance and security. ```csharp public class WorkflowAuditTrail { private readonly IAuditRepository _repository; public void AttachToEvents(IWorkflowSmith smith, IWorkflowFoundry foundry) { smith.WorkflowStarted += async (s, e) => { await _repository.LogAsync(new AuditEntry { EventType = "WorkflowStarted", WorkflowName = e.Foundry.CurrentWorkflow?.Name, ExecutionId = e.Foundry.ExecutionId, Timestamp = e.Timestamp }); }; foundry.OperationCompleted += async (s, e) => { await _repository.LogAsync(new AuditEntry { EventType = "OperationCompleted", OperationName = e.Operation.Name, Duration = e.Duration, Timestamp = e.Timestamp }); }; smith.WorkflowFailed += async (s, e) => { await _repository.LogAsync(new AuditEntry { EventType = "WorkflowFailed", Error = e.Exception?.Message, FailedOperation = e.FailedOperationName, Timestamp = e.Timestamp }); }; } } ``` -------------------------------- ### Define Operation Lifecycle Events in C# Source: https://animatlabs.com/workflow-forge/architecture/overview Defines the events for an individual operation's lifecycle, such as when it starts, completes, or fails. This interface is typically implemented by IWorkflowFoundry. ```csharp // Operation lifecycle public interface IOperationLifecycleEvents { event EventHandler? OperationStarted; event EventHandler? OperationCompleted; event EventHandler? OperationFailed; } ``` -------------------------------- ### Configure Compensation Behavior Source: https://animatlabs.com/workflow-forge/getting-started/samples-guide Demonstrates configuring compensation strategies with `FailFastCompensation` and `ThrowOnCompensationError` options. Handles compensation errors using `AggregateException`. ```csharp var options = new WorkflowForgeOptions { FailFastCompensation = true, ThrowOnCompensationError = true }; using var foundry = WorkflowForge.CreateFoundry("CompensationDemo", options: options); var workflow = WorkflowForge.CreateWorkflow("CompensationWorkflow") .AddOperation(new CompensatableOperation("StepA")) .AddOperation(new CompensatableOperation("StepB")) .AddOperation(new FailingOperation("FailurePoint")) .Build(); try { await smith.ForgeAsync(workflow, foundry); } catch (AggregateException ex) { Console.WriteLine($"Compensation errors: {ex.InnerExceptions.Count}"); } ``` -------------------------------- ### Middleware Chain Construction Source: https://animatlabs.com/workflow-forge/architecture/middleware-pipeline Shows the internal mechanism for building the middleware execution chain. It starts with the core operation and wraps each middleware in reverse order of registration. ```csharp // Start with the core operation Func> next = token => operation.ForgeAsync(inputData, this, token); // Wrap each middleware in reverse order for (int i = _middlewares.Count - 1; i >= 0; i--) { var middleware = _middlewares[i]; var currentNext = next; next = token => middleware.ExecuteAsync(operation, this, inputData, currentNext, token); } // Execute the fully-wrapped chain return await next(cancellationToken).ConfigureAwait(false); ``` -------------------------------- ### Configure Persistence with Stable Keys Source: https://animatlabs.com/workflow-forge/extensions Use stable InstanceId and WorkflowKey options to ensure deterministic foundry and workflow keys for cross-process resume. Requires a shared provider. ```csharp using WorkflowForge.Extensions; using WorkflowForge.Extensions.Persistence; var options = new PersistenceOptions { InstanceId = "order-service-west-1", // maps to a deterministic foundry key WorkflowKey = "ProcessOrder-v1" // maps to a deterministic workflow key }; using var foundry = WorkflowForge.CreateFoundry("OrderProcessing"); foundry.UsePersistence(provider, options); ```