SiLA2.StateMachine 10.2.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package SiLA2.StateMachine --version 10.2.3
                    
NuGet\Install-Package SiLA2.StateMachine -Version 10.2.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SiLA2.StateMachine" Version="10.2.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SiLA2.StateMachine" Version="10.2.3" />
                    
Directory.Packages.props
<PackageReference Include="SiLA2.StateMachine" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SiLA2.StateMachine --version 10.2.3
                    
#r "nuget: SiLA2.StateMachine, 10.2.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SiLA2.StateMachine@10.2.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SiLA2.StateMachine&version=10.2.3
                    
Install as a Cake Addin
#tool nuget:?package=SiLA2.StateMachine&version=10.2.3
                    
Install as a Cake Tool

SiLA2.StateMachine

A state machine module for orchestrating multi-step SiLA2 lab automation workflows. Built on the Stateless library, it provides a fluent API for defining workflows with automatic retry policies, OpenTelemetry tracing, and dependency injection support.

NuGet Package SiLA2.StateMachine
Repository https://gitlab.com/SiLA2/sila_csharp
SiLA Standard https://sila-standard.com
License MIT

Features

  • Fluent Builder API: Define states, transitions, and actions with method chaining
  • Async Entry/Exit Actions: Execute SiLA2 service calls on state transitions
  • Workflow Context: Thread-safe data sharing between workflow steps
  • Retry Policies: Configurable retry with constant or exponential backoff
  • Auto-Advance: Automatic state progression via completion triggers
  • Progress Events: Subscribe to workflow state changes and errors
  • OpenTelemetry: Built-in tracing via ActivitySource
  • DOT Graph Export: Visualize state machines with Graphviz

Installation

dotnet add package SiLA2.StateMachine

Platform Compatibility

Target Framework Supported
.NET 10.0+ Yes (full feature support)
.NET Standard 2.0 Yes
.NET Framework 4.6.1+ Yes (via netstandard2.0)
.NET Core 2.0+ Yes (via netstandard2.0)

This package multi-targets net10.0 and netstandard2.0, allowing it to be used from both modern .NET and legacy .NET Framework projects.

Quick Start

using SiLA2.StateMachine;
using SiLA2.StateMachine.Models;

// Define states and triggers
enum State { Idle, Processing, Done, Error }
enum Trigger { Start, Complete, Fault }

// Build workflow
var workflow = new SilaWorkflowBuilder<State, Trigger>()
    .StartIn(State.Idle)
    .Permit(State.Idle, Trigger.Start, State.Processing)
    .Permit(State.Processing, Trigger.Complete, State.Done)
    .Permit(State.Processing, Trigger.Fault, State.Error)
    .InState(State.Processing)
        .OnEntry(async (ctx, sp, ct) =>
        {
            // Call SiLA2 services here
            ctx.Set("result", 42);
        })
        .OnCompleted(Trigger.Complete)
        .OnError(Trigger.Fault, maxRetries: 3, retryDelayMs: 1000)
    .Build();

// Run workflow
await workflow.FireAsync(Trigger.Start);

Console.WriteLine($"State: {workflow.CurrentState}");  // Done
Console.WriteLine($"Result: {workflow.Context.Get<int>("result")}");  // 42

Core Concepts

States and Triggers

States and triggers are defined as enums (or structs). The workflow transitions between states when triggers are fired.

enum AssayState { Idle, Aspirating, Dispensing, Incubating, Measuring, Done, Error }
enum AssayTrigger { Start, AspirateComplete, DispenseComplete, IncubateComplete, MeasureComplete, Fault }

Workflow Builder

Use the fluent builder to configure states, transitions, and actions:

var workflow = new SilaWorkflowBuilder<AssayState, AssayTrigger>()
    .StartIn(AssayState.Idle)

    // Define transitions
    .Permit(AssayState.Idle, AssayTrigger.Start, AssayState.Aspirating)
    .Permit(AssayState.Aspirating, AssayTrigger.AspirateComplete, AssayState.Dispensing)

    // Configure state behavior
    .InState(AssayState.Aspirating)
        .WithDescription("Aspirate sample from source plate")
        .OnEntry(async (ctx, sp, ct) =>
        {
            var liquidHandler = sp.GetRequiredService<ILiquidHandlerClient>();
            await liquidHandler.AspirateAsync(100.0, ct);
            ctx.Set("aspiratedVolume", 100.0);
        })
        .OnCompleted(AssayTrigger.AspirateComplete)
        .OnError(AssayTrigger.Fault, maxRetries: 2, retryDelayMs: 1000)

    .Build(services, logger);

Workflow Context

The IWorkflowContext is a thread-safe data bag for passing values between states:

// In state A
ctx.Set("temperature", 37.5);
ctx.Set("sampleId", "SAMPLE-001");

// In state B
var temp = ctx.Get<double>("temperature");
if (ctx.TryGet<string>("sampleId", out var id))
{
    Console.WriteLine($"Processing {id}");
}

Error Policies

Configure retry behavior for transient failures:

.InState(State.Measuring)
    .OnEntry(async (ctx, sp, ct) => { /* may fail */ })
    .OnError(Trigger.Fault, WorkflowErrorPolicy.ExponentialBackoff(
        maxRetries: 5,
        initialDelay: TimeSpan.FromSeconds(1),
        multiplier: 2.0))
Policy Description
NoRetry Fail immediately (default)
SimpleRetry(n, delay) Retry n times with constant delay
ExponentialBackoff(n, delay, mult) Retry with increasing delays

Progress Events

Subscribe to workflow progress:

workflow.ProgressChanged += (sender, progress) =>
{
    Console.WriteLine($"{progress.FromState} → {progress.ToState}");
    if (progress.Exception != null)
        Console.WriteLine($"Error: {progress.Exception.Message}");
};

ASP.NET Core Integration

// Program.cs
using SiLA2.StateMachine.Extensions;

builder.Services.AddSilaStateMachine();

// Or register a pre-configured workflow
builder.Services.AddSilaWorkflow<AssayState, AssayTrigger>(builder =>
{
    builder
        .StartIn(AssayState.Idle)
        .Permit(AssayState.Idle, AssayTrigger.Start, AssayState.Processing)
        // ... configure workflow
});
// In a controller or service
public class AssayController
{
    private readonly SilaWorkflowBuilder<AssayState, AssayTrigger> _builder;
    private readonly IServiceProvider _services;
    private readonly ILogger<AssayController> _logger;

    public AssayController(
        SilaWorkflowBuilder<AssayState, AssayTrigger> builder,
        IServiceProvider services,
        ILogger<AssayController> logger)
    {
        _builder = builder;
        _services = services;
        _logger = logger;
    }

    public async Task<IActionResult> RunAssay()
    {
        var workflow = _builder.Build(_services, _logger);
        await workflow.FireAsync(AssayTrigger.Start);
        return Ok(new { Status = workflow.Status, State = workflow.CurrentState });
    }
}

OpenTelemetry Integration

The library emits traces via System.Diagnostics.ActivitySource:

// Subscribe to workflow traces
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing.AddSource("SiLA2.StateMachine");  // Activity source name
    });

Traced activities:

  • Workflow.Run - Full workflow execution
  • Workflow.Fire - Individual trigger firing
  • Workflow.StateEntry - State entry action execution (with retry attempts)

Advanced Patterns

Hierarchical States

.SubstateOf(State.Processing, State.Running)

Conditional Transitions

.PermitIf(State.Idle, Trigger.Start, State.FastPath,
    () => _config.UseFastPath, "Fast path enabled")
.PermitIf(State.Idle, Trigger.Start, State.SlowPath,
    () => !_config.UseFastPath, "Slow path enabled")

DOT Graph Export

Generate Graphviz diagrams:

var dotGraph = workflow.ToDotGraph();
File.WriteAllText("workflow.dot", dotGraph);
// Render with: dot -Tpng workflow.dot -o workflow.png

Builder Methods

Method Description
StartIn(state) Set initial state (required)
InState(state) Begin configuring a state
WithDescription(text) Add description to current state
OnEntry(action) Async action when entering state
OnExit(action) Async action when leaving state
OnCompleted(trigger) Auto-fire trigger after successful entry
OnError(trigger, policy) Error trigger and retry policy
Permit(from, trigger, to) Define transition
PermitIf(from, trigger, to, guard) Conditional transition
PermitReentry(state, trigger) Self-transition
Ignore(state, trigger) Ignore trigger in state
SubstateOf(sub, super) Hierarchical state
Build(services, logger, context) Create workflow instance

Workflow Status

Status Description
Created Workflow built but not started
Running Workflow is executing
Paused Workflow paused (reserved)
Completed All states finished successfully
Aborted Workflow aborted via AbortAsync()
Faulted Unrecoverable error occurred

Working Example

See the complete plate assay workflow example:

Path: src/Examples/WorkflowOrchestration/

dotnet run --project src/Examples/WorkflowOrchestration/SiLA2.StateMachine.Example.csproj

This example demonstrates:

  • Multi-step lab workflow (Discover → Aspirate → Dispense → Incubate → Measure → Report)
  • Service discovery simulation
  • Context data passing between states
  • Retry policies for transient failures
  • Progress event handling
  • Serilog logging integration

Troubleshooting

Error Cause Solution
Initial state not set Missing StartIn() Call StartIn(state) before Build()
No state selected Missing InState() Call InState(state) before OnEntry()
Trigger not permitted Invalid transition Check CanFire() or add Permit()
Max auto-advance depth Infinite loop Ensure workflow reaches terminal state

License

MIT License - See LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.2.4 77 3/13/2026
10.2.3 67 3/10/2026