### Install Dependencies and Serve Jekyll Site Locally Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/README.md Run these commands from the `docs/` directory to install dependencies and start a local Jekyll server for previewing the site. The site will be accessible at `http://localhost:4000/`. ```bash bundle install bundle exec jekyll serve --config _config.yml ``` -------------------------------- ### Quick Start: Create WorkflowForge Foundry with Serilog Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Logging.Serilog/README.md Initialize Serilog with basic options and create a WorkflowForge foundry. This example sets the minimum log level to Information and enables the console sink. ```csharp using WorkflowForge; using WorkflowForge.Extensions.Logging.Serilog; var logger = SerilogLoggerFactory.CreateLogger(new SerilogLoggerOptions { MinimumLevel = "Information", EnableConsoleSink = true }); using var foundry = WorkflowForge.CreateFoundry("MyWorkflow", logger); ``` -------------------------------- ### Install WorkflowForge.Extensions.Persistence Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Persistence/README.md Add the persistence package to your .NET project. ```bash dotnet add package WorkflowForge.Extensions.Persistence ``` -------------------------------- ### Install WorkflowForge.Extensions.Resilience.Polly Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Resilience.Polly/README.md Add the Polly resilience extension package to your .NET project. ```bash dotnet add package WorkflowForge.Extensions.Resilience.Polly ``` -------------------------------- ### Development Setup for WorkflowForge Source: https://github.com/animatlabs/workflow-forge/blob/main/CONTRIBUTING.md Clone the repository, restore dependencies, and build the project. Run tests to ensure code integrity. ```bash git clone https://github.com/animatlabs/workflow-forge.git cd workflow-forge dotnet restore dotnet build -c Release dotnet test -c Release ``` -------------------------------- ### Execute Workflow with Smith and Foundry Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example demonstrating how to create a smith, create a foundry for a workflow, and then execute the workflow using the smith and foundry. ```csharp using var smith = WorkflowForge.CreateSmith(); using var foundry = smith.CreateFoundryFor(workflow); await smith.ForgeAsync(workflow, foundry); ``` -------------------------------- ### Install WorkflowForge.Testing Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/core/WorkflowForge.Testing/README.md Add the WorkflowForge.Testing NuGet package to your project to enable testing utilities. ```bash dotnet add package WorkflowForge.Testing ``` -------------------------------- ### Example: AuditedOperation Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md An example demonstrating how to extend `WorkflowOperationBase` to create a custom operation with logging hooks. ```APIDOC ## AuditedOperation Example ### Description This example shows a custom operation `AuditedOperation` that extends `WorkflowOperationBase` and utilizes lifecycle hooks (`OnBeforeExecuteAsync`, `OnAfterExecuteAsync`) to log operation start and completion. ### Class Definition ```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; } // Placeholder for actual operation logic private Task ProcessAsync(object? inputData, CancellationToken ct) { // Replace with your actual processing logic return Task.FromResult($"Processed: {inputData}"); } } ``` ### Usage Recommendation `WorkflowOperationBase` is the recommended base class for most custom workflow steps due to its built-in features and lifecycle management. ``` -------------------------------- ### Create and Run a Simple Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/samples-guide.md Demonstrates the minimal setup for creating a workflow with a single inline operation and executing it using a workflow smith. ```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); ``` -------------------------------- ### TimingMiddleware Implementation Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example implementation of IWorkflowOperationMiddleware to measure the execution time of an operation. It starts a stopwatch before calling the next delegate and logs the elapsed time. ```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); } } } ``` -------------------------------- ### Quick Start: Wrap Operation with Exponential Backoff Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Resilience/README.md Wrap a workflow operation with exponential backoff retry logic for external service calls. This example demonstrates setting base delay, max delay, and max attempts. ```csharp using WorkflowForge; using WorkflowForge.Extensions.Resilience; using WorkflowForge.Extensions.Resilience.Strategies; // Wrap operations with retry logic var resilientOperation = RetryWorkflowOperation.WithExponentialBackoff( operation: myOperation, baseDelay: TimeSpan.FromMilliseconds(100), maxDelay: TimeSpan.FromSeconds(30), maxAttempts: 3); // Use in workflow var workflow = WorkflowForge.CreateWorkflow("ProcessOrder") .AddOperation(resilientOperation) .Build(); await smith.ForgeAsync(workflow, foundry); ``` -------------------------------- ### Install WorkflowForge.Extensions.Validation Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Validation/README.md Add the validation package to your project using the .NET CLI. ```bash dotnet add package WorkflowForge.Extensions.Validation ``` -------------------------------- ### Install Resilience Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Resilience/README.md Add the WorkflowForge.Extensions.Resilience NuGet package to your project. ```bash dotnet add package WorkflowForge.Extensions.Resilience ``` -------------------------------- ### Install WorkflowForge Serilog Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Logging.Serilog/README.md Use the dotnet CLI to add the Serilog extension package to your project. ```bash dotnet add package WorkflowForge.Extensions.Logging.Serilog ``` -------------------------------- ### Add WorkflowForge Package Source: https://github.com/animatlabs/workflow-forge/blob/main/README.md Install the core WorkflowForge NuGet package using the .NET CLI. ```bash dotnet add package WorkflowForge ``` -------------------------------- ### AuditedOperation Example with Lifecycle Hooks Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example of a custom workflow operation inheriting from WorkflowOperationBase, demonstrating the use of OnBeforeExecuteAsync and OnAfterExecuteAsync for logging. ```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; } } ``` -------------------------------- ### Dependency Inversion Principle Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/architecture/overview.md Illustrates the Dependency Inversion Principle by defining core abstractions and their concrete implementations. This promotes loose coupling. ```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 Dependency Injection Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.DependencyInjection/README.md Add the WorkflowForge.Extensions.DependencyInjection NuGet package to your project using the .NET CLI. ```bash dotnet add package WorkflowForge.Extensions.DependencyInjection ``` -------------------------------- ### Enable Performance Monitoring and Get Statistics Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/samples-guide.md Enable performance monitoring to track duration and allocation counters using `EnablePerformanceMonitoring` and `GetPerformanceStatistics`. ```csharp foundry.EnablePerformanceMonitoring(); var stats = foundry.GetPerformanceStatistics(); Console.WriteLine($"Total Duration: {stats.TotalDuration}ms"); Console.WriteLine($"Memory Allocated: {stats.TotalMemoryAllocated}KB"); ``` -------------------------------- ### Quick Start: Create and Run Health Checks Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Observability.HealthChecks/README.md Initialize the health check service from a foundry and run all registered checks. Displays overall status and individual check results. ```csharp using WorkflowForge; using WorkflowForge.Extensions.Observability.HealthChecks; using var foundry = WorkflowForge.CreateFoundry("MonitoredWorkflow"); // Create the health check service from the foundry var healthService = foundry.CreateHealthCheckService( checkInterval: TimeSpan.FromSeconds(30)); // Run all registered health checks var results = await healthService.CheckHealthAsync(); Console.WriteLine($"Overall status: {healthService.OverallStatus}"); foreach (var (name, result) in results) { Console.WriteLine($" {name}: {result.Status} - {result.Description}"); } ``` -------------------------------- ### Add WorkflowForge Packages Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/getting-started.md Install the core WorkflowForge package and optional extension packages using the .NET CLI. These packages provide the necessary tools for building workflows. ```bash dotnet add package WorkflowForge # Optional 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 ``` -------------------------------- ### Dependency Injection Setup with Workflow Forge Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/samples-guide.md Shows how to configure dependency injection for Workflow Forge, including registering services and resolving the IWorkflowSmith. ```csharp var services = new ServiceCollection(); services.AddSingleton(configuration); services.AddSingleton(_ => new ConsoleLogger("WF-DI")); services.AddWorkflowForge(configuration); services.AddWorkflowSmith(); services.AddSingleton(); using var provider = services.BuildServiceProvider(); var smith = provider.GetRequiredService(); var workflow = WorkflowForge.CreateWorkflow("DiConfiguredWorkflow") .AddOperation(new GenerateOrderIdOperation()) .Build(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### Basic Workflow Event Subscription Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Demonstrates how to subscribe to basic workflow events like Started, Completed, and Failed using C# event handlers. ```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); ``` -------------------------------- ### Code-Configured Polly Options for Foundry Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Resilience.Polly/README.md Configure Polly middleware options programmatically for a foundry. This example demonstrates setting retry, circuit breaker, and timeout policies directly in code. ```csharp var options = new PollyMiddlewareOptions { Enabled = true, Retry = { IsEnabled = true, MaxRetryAttempts = 5, BaseDelay = TimeSpan.FromSeconds(2) }, CircuitBreaker = { IsEnabled = true, FailureThreshold = 10 }, Timeout = { IsEnabled = true, DefaultTimeout = TimeSpan.FromSeconds(60) } }; foundry.UsePollyFromSettings(options); ``` -------------------------------- ### Install Persistence Recovery Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Persistence.Recovery/README.md Add the WorkflowForge.Extensions.Persistence.Recovery NuGet package to your project. This package targets .NET Standard 2.0 or later and requires a shared IWorkflowPersistenceProvider. ```bash dotnet add package WorkflowForge.Extensions.Persistence.Recovery ``` -------------------------------- ### Create a Workflow Builder Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Use `CreateWorkflow` to start building a new workflow. You can optionally provide a name and an `IServiceProvider` for dependency injection. The builder allows for fluent configuration of operations. ```csharp public static WorkflowBuilder CreateWorkflow(string? workflowName = null, IServiceProvider? serviceProvider = null) ``` ```csharp var workflow = WorkflowForge.CreateWorkflow("OrderProcessing") .AddOperation(new ValidateOperation()) .Build(); ``` -------------------------------- ### Create and Execute a Simple Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/README.md Demonstrates building a basic 'Hello World' workflow with a single operation and executing it using the WorkflowForge smith. ```csharp using WorkflowForge; // Build workflow var workflow = WorkflowForge.CreateWorkflow("HelloWorld") .AddOperation("SayHello", async (foundry, ct) => { foundry.Logger.LogInformation("Hello, WorkflowForge!"); await Task.CompletedTask; }) .Build(); // Execute workflow using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### Subscribe to Operation Lifecycle Events Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example of subscribing to operation lifecycle events to log when operations start and complete. Ensure the 'foundry' object is an instance of a class implementing IOperationLifecycleEvents. ```csharp foundry.OperationStarted += (s, e) => Console.WriteLine($"Operation {e.Operation.Name} started"); foundry.OperationCompleted += (s, e) => Console.WriteLine($"Operation {e.Operation.Name} completed"); ``` -------------------------------- ### Run Basic Console Samples Source: https://github.com/animatlabs/workflow-forge/blob/main/src/samples/WorkflowForge.Samples.BasicConsole/README.md Navigate to the sample directory and run the console application to access the menu. ```bash cd src/samples/WorkflowForge.Samples.BasicConsole dotnet run ``` -------------------------------- ### Run Basic Console Sample Source: https://github.com/animatlabs/workflow-forge/blob/main/src/samples/README.md Navigate to the BasicConsole sample directory and run the application using the .NET CLI. Use the interactive menu to select and execute individual samples. ```bash cd WorkflowForge.Samples.BasicConsole dotnet run ``` -------------------------------- ### Custom Operation with Lifecycle Hooks Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/operations.md Enhance operations with cross-cutting concerns like auditing using `OnBeforeExecuteAsync` and `OnAfterExecuteAsync`. This example logs the start and end times of an operation, demonstrating how to use lifecycle hooks without modifying the core business logic in `ForgeAsyncCore`. ```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}", Name); foundry.Properties["StartTime"] = DateTime.UtcNow; return Task.CompletedTask; } protected override async Task ForgeAsyncCore( object? inputData, IWorkflowFoundry foundry, CancellationToken ct) { // Pure business logic return await ProcessDataAsync(inputData, ct); } protected override Task OnAfterExecuteAsync( object? inputData, object? outputData, IWorkflowFoundry foundry, CancellationToken ct) { var duration = DateTime.UtcNow - (DateTime)foundry.Properties["StartTime"]!; foundry.Logger.LogInformation("Completed {Operation} in {Duration}ms", Name, duration.TotalMilliseconds); return Task.CompletedTask; } } ``` -------------------------------- ### Run All Benchmarks Source: https://github.com/animatlabs/workflow-forge/blob/main/src/benchmarks/WorkflowForge.Benchmarks/README.md Navigate to the benchmark directory and execute all benchmarks in Release configuration. ```bash cd src/benchmarks/WorkflowForge.Benchmarks dotnet run -c Release ``` -------------------------------- ### OperationRestoreStartedEventArgs Definition Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Defines the arguments for an operation restore started event. Includes the operation and the start time. ```csharp public class OperationRestoreStartedEventArgs : BaseWorkflowForgeEventArgs { public IWorkflowOperation Operation { get; } public DateTimeOffset StartedAt { get; } } ``` -------------------------------- ### TimeSensitiveOperation Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example of an operation that depends on the system time. It injects ISystemTimeProvider to allow for time-based logic that can be controlled during testing. ```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; } } ``` -------------------------------- ### Create Foundry with Initial Properties and Options Source: https://context7.com/animatlabs/workflow-forge/llms.txt Use CreateFoundry to establish an execution context with initial shared properties and custom workflow options. Dispose of the foundry after use. ```csharp using WorkflowForge; // Foundry with initial properties and custom options var options = new WorkflowForgeOptions { ContinueOnError = false, FailFastCompensation = false, ThrowOnCompensationError = true, EnableOutputChaining = true, MaxConcurrentWorkflows = 10 }; using var foundry = WorkflowForge.CreateFoundry( workflowName: "InvoiceRun", initialProperties: new Dictionary { ["InvoiceId"] = "INV-2026-001", ["CustomerId"] = "CUST-99", ["Amount"] = 500.00m }, options: options); // Read and write properties during a workflow foundry.SetProperty("ProcessedAt", DateTimeOffset.UtcNow); var invoiceId = foundry.GetPropertyOrDefault("InvoiceId"); // "INV-2026-001" var missing = foundry.GetPropertyOrDefault("NoSuchKey", "default"); // "default" Console.WriteLine($"ExecutionId: {foundry.ExecutionId}"); // unique Guid per run ``` -------------------------------- ### Custom Workflow Operation Example Source: https://github.com/animatlabs/workflow-forge/blob/main/src/core/WorkflowForge/README.md Example of a custom workflow operation that calculates a total based on items in the foundry's properties and logs the result. Subclass `WorkflowOperationBase` and override `ForgeAsyncCore`. ```csharp public class CalculateTotalOperation : WorkflowOperationBase { public override string Name => "CalculateTotal"; protected override async Task ForgeAsyncCore( object? inputData, IWorkflowFoundry foundry, CancellationToken cancellationToken = default) { var items = foundry.GetPropertyOrDefault>("Items"); var total = items.Sum(x => x.Price * x.Quantity); foundry.SetProperty("Total", total); foundry.Logger.LogInformation("Calculated total: {Total}", total); return total; } } ``` -------------------------------- ### FakeWorkflowFoundry Example: Asserting Operation Execution Count Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example of using FakeWorkflowFoundry to verify that a sequence of operations is executed. Add operations to the foundry, forge the workflow, and assert the count of executed operations. ```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); } ``` -------------------------------- ### Clone and Run Workflow Forge Samples Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/getting-started.md Instructions for cloning the Workflow Forge repository and running the basic console sample application to see the workflow engine in action. ```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 ``` -------------------------------- ### FakeWorkflowFoundry Example: Asserting Property Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Example of using FakeWorkflowFoundry to test if an operation sets a property. Arrange the foundry and operation, act by forging the operation, and assert the property's presence and value. ```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"]); } ``` -------------------------------- ### Run Comparative Benchmarks Source: https://github.com/animatlabs/workflow-forge/blob/main/src/benchmarks/WorkflowForge.Benchmarks.Comparative/README.md Execute all comparative benchmarks for the project. Ensure the configuration is set to 'Release' for accurate results. Artifacts will be saved in the 'BenchmarkDotNet.Artifacts/' directory. ```bash dotnet run --project WorkflowForge.Benchmarks.Comparative.csproj --configuration Release ``` -------------------------------- ### Build the .NET Project Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/getting-started.md Compile your .NET project to ensure all dependencies are correctly resolved and the project builds successfully. ```bash dotnet build ``` -------------------------------- ### Create and Execute Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/index.md Demonstrates how to create a simple workflow with a single operation and execute it using WorkflowForge. ```APIDOC ## Create and Execute Workflow ### Description This example shows the basic usage of WorkflowForge to define a workflow named "HelloWorld" with an operation that logs a message. It then uses `WorkflowForge.CreateSmith()` to get an execution engine and `smith.ForgeAsync()` to run the workflow. ### Usage ```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); ``` ``` -------------------------------- ### Create and Execute a Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/src/core/WorkflowForge/README.md Defines a sample workflow with several operations, sets up an execution environment with properties, and executes the workflow using a smith. Results are read from the foundry properties. ```csharp using WorkflowForge; using WorkflowForge.Extensions; // Create workflow var workflow = WorkflowForge.CreateWorkflow("OrderProcessing") .AddOperation(new ValidateOrderOperation()) .AddOperation(new ChargePaymentOperation()) .AddOperation(new ReserveInventoryOperation()) .AddOperation(new CreateShipmentOperation()) .Build(); // Create execution environment using var foundry = WorkflowForge.CreateFoundry("Order-12345"); foundry.SetProperty("OrderId", "12345"); foundry.SetProperty("CustomerId", "CUST-001"); // Execute workflow using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow, foundry); // Read results var shipmentId = foundry.GetPropertyOrDefault("ShipmentId"); ``` -------------------------------- ### Create Production Foundry with Logging Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/configuration.md Create a workflow foundry configured for a production environment. This involves setting up Serilog to log at the 'Information' level with console output. ```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); } } ``` -------------------------------- ### OperationStartedEventArgs Definition Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Defines the arguments for an operation started event. Includes the operation and its input data. ```csharp public class OperationStartedEventArgs : BaseWorkflowForgeEventArgs { public IWorkflowOperation Operation { get; } public object? InputData { get; } } ``` -------------------------------- ### Create and Run a Workflow with Data Passing Source: https://github.com/animatlabs/workflow-forge/blob/main/README.md Demonstrates how to define a workflow with multiple operations, passing data between them using the foundry. Set and get properties on the foundry to share context. This workflow loads an order, validates it, and processes payment. ```csharp var workflow = WorkflowForge.CreateWorkflow("ProcessOrder") .AddOperation("LoadOrder", async (foundry, ct) => { var order = await LoadOrderFromDb(); foundry.SetProperty("Order", order); }) .AddOperation("ValidateOrder", async (foundry, ct) => { var order = foundry.GetPropertyOrDefault("Order"); if (order == null) throw new InvalidOperationException("Order not found"); // Validation logic }) .AddOperation("ProcessPayment", async (foundry, ct) => { var order = foundry.GetPropertyOrDefault("Order"); var result = await ProcessPayment(order); foundry.SetProperty("PaymentResult", result); }) .Build(); using var smith = WorkflowForge.CreateSmith(); await smith.ForgeAsync(workflow); ``` -------------------------------- ### WorkflowStartedEventArgs Definition Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Defines the arguments for a workflow started event. Includes the timestamp when the workflow began. ```csharp public class WorkflowStartedEventArgs : BaseWorkflowForgeEventArgs { public DateTimeOffset StartedAt { get; } } ``` -------------------------------- ### Integrate Custom Extension with Foundry Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/extensions/index.md Demonstrates how to set up a custom extension within the Foundry and use it in a workflow. Ensure the service provider is configured to resolve the extension. ```csharp public class ExtensionIntegrationTests { [Fact] public async Task Should_Integrate_With_Foundry_Successfully() { // Arrange var foundry = WorkflowForge.CreateFoundry("Test") .UseCustomExtension(); var workflow = WorkflowForge.CreateWorkflow() .WithName("TestWorkflow") .AddOperation(new ActionWorkflowOperation( "TestOp", async (input, foundry, ct) => { var extension = foundry.ServiceProvider ?.GetRequiredService() ?? throw new InvalidOperationException("Service provider is required."); var value = foundry.GetPropertyOrDefault("Input"); var result = await extension.ProcessAsync(value); foundry.SetProperty("Result", result); } )) .Build(); var smith = WorkflowForge.CreateSmith(); // Act foundry.SetProperty("Input", "test"); await smith.ForgeAsync(workflow, foundry); // Assert var result = foundry.GetPropertyOrDefault("Result"); Assert.NotNull(result); } } ``` -------------------------------- ### Delay Operation Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/operations.md Implement a delay in the workflow using DelayOperation, which is equivalent to Task.Delay. It honors the CancellationToken. ```csharp var workflow = WorkflowForge.CreateWorkflow() .WithName("PollingWorkflow") .AddOperation(new DelegateWorkflowOperation( "CheckStatus", async (input, foundry, ct) => { var status = await _service.GetStatusAsync(); foundry.Properties["Status"] = status; return status; } )) .AddOperation(new DelayOperation(TimeSpan.FromSeconds(5), "WaitBeforeRetry")) .AddOperation(new DelegateWorkflowOperation( "RetryCheck", async (input, foundry, ct) => { // Retry logic return input; } )) .Build(); ``` -------------------------------- ### Create and Execute a Simple Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/index.md Defines and executes a basic 'HelloWorld' workflow using Workflow Forge. Ensure the WorkflowForge package is added. ```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); ``` -------------------------------- ### Programmatic Usage of Resilience Strategies Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Resilience/README.md Demonstrates programmatic configuration of retry logic using both the convenience factory method WithExponentialBackoff and by explicitly creating strategy instances like ExponentialBackoffStrategy. ```csharp using WorkflowForge.Extensions.Resilience; using WorkflowForge.Extensions.Resilience.Strategies; // Wrap operations with retry logic var resilientOperation = RetryWorkflowOperation.WithExponentialBackoff( operation: myOperation, baseDelay: TimeSpan.FromMilliseconds(100), maxDelay: TimeSpan.FromSeconds(30), maxAttempts: 3); // Or use specific strategies var strategy = new ExponentialBackoffStrategy( baseDelay: TimeSpan.FromSeconds(1), maxDelay: TimeSpan.FromSeconds(60), maxAttempts: 5, logger: logger); var resilientOp = new RetryWorkflowOperation(myOperation, strategy); // Add to workflow var workflow = WorkflowForge.CreateWorkflow("ResilientProcess") .AddOperation(resilientOp) .Build(); ``` -------------------------------- ### Install Health Checks Package Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Observability.HealthChecks/README.md Add the health checks package to your project using the .NET CLI. ```bash dotnet add package WorkflowForge.Extensions.Observability.HealthChecks ``` -------------------------------- ### Create a Workflow Foundry Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/reference/api-reference.md Instantiate an `IWorkflowFoundry` using `CreateFoundry`. This provides an execution context and accepts optional parameters like a logger, initial properties, and workflow options. Ensure to dispose of the foundry when done. ```csharp public static IWorkflowFoundry CreateFoundry( string workflowName, IWorkflowForgeLogger? logger = null, IDictionary? initialProperties = null, WorkflowForgeOptions? options = null) ``` ```csharp using var foundry = WorkflowForge.CreateFoundry("MyFoundry", logger, initialProperties, options); ``` -------------------------------- ### Operation Event Subscription Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Shows how to subscribe to operation events such as Started, Completed, and Failed when using a Workflow Foundry. ```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); ``` -------------------------------- ### Operation Lifecycle Events Interface Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Defines events for individual operation lifecycles, covering start, completion, and failure. ```csharp public interface IOperationLifecycleEvents { event EventHandler? OperationStarted; event EventHandler? OperationCompleted; event EventHandler? OperationFailed; } ``` -------------------------------- ### Run Competitive Benchmarks Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/performance/performance.md Execute comparative performance benchmarks. Navigate to the comparative benchmarks directory and run the dotnet command. Full runs may take 30-60 minutes. ```bash cd src/benchmarks/WorkflowForge.Benchmarks.Comparative dotnet run -c Release ``` -------------------------------- ### Complex Validation Rules Example Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Validation/README.md Demonstrates a more complex Order class with multiple validation attributes and custom IValidatableObject logic. ```csharp public class Order : IValidatableObject { [Required] public string CustomerId { get; set; } = string.Empty; [Range(0.01, 10000)] public decimal Amount { get; set; } [EmailAddress] public string? Email { get; set; } public IEnumerable Validate(ValidationContext context) { if (CustomerId.Length < 5) yield return new System.ComponentModel.DataAnnotations.ValidationResult( "Customer ID must be at least 5 characters", new[] { nameof(CustomerId) }); } } ``` -------------------------------- ### Build and Run an Order Processing Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/getting-started.md This C# code demonstrates building a complete order processing workflow with Validate, Process Payment, and Fulfill operations. It initializes an order, creates a workflow, sets up a foundry with initial data, and executes the workflow using a smith with a console logger. Error handling is included. ```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}"); } ``` -------------------------------- ### Workflow Lifecycle Events Interface Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/events.md Defines events for the workflow's overall lifecycle, including start, completion, and failure. ```csharp public interface IWorkflowLifecycleEvents { event EventHandler? WorkflowStarted; event EventHandler? WorkflowCompleted; event EventHandler? WorkflowFailed; } ``` -------------------------------- ### Create Development Foundry with Logging and Timing Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/configuration.md Create a workflow foundry configured for a development environment. This includes setting up Serilog for debugging with console output and enabling the timing middleware. ```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; } } ``` -------------------------------- ### Workflow Forge Audit Configuration Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/extensions/index.md Example JSON configuration for enabling audit logging, including metadata, and setting a default initiator. ```json { "WorkflowForge": { "Audit": { "Enabled": true, "IncludeMetadata": true, "DefaultInitiatedBy": "system" } } } ``` -------------------------------- ### Create a new .NET Console Application Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/getting-started/getting-started.md Use the .NET CLI to create a new console application for your workflow project. Navigate into the newly created directory. ```bash dotnet new console -n MyWorkflowApp cd MyWorkflowApp ``` -------------------------------- ### Focused Operations Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/operations.md Illustrates the guideline of keeping operations focused on a single task. This promotes modularity and maintainability 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 }) ``` -------------------------------- ### Create Basic Workflow Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/core/configuration.md Use this pattern for simple workflows with default settings. It involves creating a workflow, adding operations, and then executing 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); ``` -------------------------------- ### Database Audit Provider Implementation Source: https://github.com/animatlabs/workflow-forge/blob/main/src/extensions/WorkflowForge.Extensions.Audit/README.md An example implementation of `IAuditProvider` that writes audit entries to a database using Dapper for data access. ```csharp public class DatabaseAuditProvider : IAuditProvider { private readonly IDbConnection _connection; public async Task WriteAuditEntryAsync(AuditEntry entry, CancellationToken cancellationToken = default) { await _connection.ExecuteAsync( "INSERT INTO AuditLog (AuditId, Timestamp, ExecutionId, WorkflowName, OperationName, EventType, InitiatedBy, Status, ErrorMessage, DurationMs) VALUES (@AuditId, @Timestamp, @ExecutionId, @WorkflowName, @OperationName, @EventType, @InitiatedBy, @Status, @ErrorMessage, @DurationMs)", entry, cancellationToken); } public Task FlushAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; } ``` -------------------------------- ### SRP Adherence Example Source: https://github.com/animatlabs/workflow-forge/blob/main/docs/architecture/overview.md Shows the WorkflowForge design adhering to the Single Responsibility Principle by separating event types into distinct interfaces. ```csharp // Three focused interfaces public interface IWorkflowLifecycleEvents { /* workflow events */ } public interface IOperationLifecycleEvents { /* operation events */ } public interface ICompensationLifecycleEvents { /* compensation events */ } ```