Optima.Net.StateMachines 3.0.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Optima.Net.StateMachines --version 3.0.0
                    
NuGet\Install-Package Optima.Net.StateMachines -Version 3.0.0
                    
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="Optima.Net.StateMachines" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Optima.Net.StateMachines" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Optima.Net.StateMachines" />
                    
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 Optima.Net.StateMachines --version 3.0.0
                    
#r "nuget: Optima.Net.StateMachines, 3.0.0"
                    
#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 Optima.Net.StateMachines@3.0.0
                    
#: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=Optima.Net.StateMachines&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Optima.Net.StateMachines&version=3.0.0
                    
Install as a Cake Tool

Optima.Net.StateMachines

Optima.Net.StateMachines is a lightweight, declarative, and idempotent state machine framework for .NET 8 and later.

It models event-driven lifecycles in a passive and deterministic way:

  • transitions are declared as data
  • undefined transitions are ignored
  • applying the same event multiple times yields the same state

This package is domain-agnostic and contains no persistence, infrastructure, or orchestration code.


Overview

Core principles:

  • Declarative configuration (event → from → to)
  • Passive semantics (undefined transitions are ignored)
  • Idempotent operations
  • Deterministic evaluation
  • Stateless by default
  • Extensible token model (no enums)
  • Explicit, type-safe aggregation (major version change)

IMPORTANT: Aggregation Model (Major Version Change)

Aggregation was redesigned in a major release.

Aggregation no longer operates on raw StateToken values.

Instead, aggregation is explicit and type-safe:

  • Machines must explicitly opt in to aggregation
  • State access is decoupled from state ownership
  • Aggregators work with stateless and stateful machines
  • Aggregation eligibility is enforced by the type system

Key abstractions:

  • IAggregatableStateMachine � permission to participate in aggregation
  • IStateProvider � access to a state value
  • IStateAggregator � authority that derives aggregate meaning

PART A: STATELESS STATE MACHINES (CALCULATOR MODEL)

Stateless state machines do not track internal state. They calculate a next state when given a transition and a current state.

This model is ideal when:

  • state is persisted externally
  • workflows are event-sourced
  • replay and rehydration are required
  • machines must remain pure and side-effect free

PART B: STATEFUL STATE MACHINE INSTANCES (NEW IN 3.0.0)

In addition to stateless machines, Optima.Net.StateMachines now supports stateful state machine instances.

A stateful machine instance:

  • owns its current state
  • applies transitions directly
  • exposes its state via IStateProvider
  • can participate in aggregation without adapters

  1. Define a Stateful Machine Instance

public sealed class OrderStateMachineInstance :
    IAggregatableStateMachine,
    IStateProvider
{
    private readonly OrderStateMachine _machine;

    public OrderState CurrentState { get; private set; }

    public OrderStateMachineInstance(OrderState initialState)
    {
        _machine = new OrderStateMachine();
        CurrentState = initialState;
    }

    public void Apply(OrderTransition transition)
    {
        CurrentState = _machine.Apply(transition, CurrentState);
    }

    public StateToken GetCurrentState()
        => CurrentState;
}

  1. Using a Stateful Machine in Application Code

var order = new OrderStateMachineInstance(OrderState.New);

order.Apply(OrderTransition.Create);
order.Apply(OrderTransition.Pay);
order.Apply(OrderTransition.Ship);

Console.WriteLine(order.CurrentState);

  1. Aggregating Stateful Machine Instances

var order = new OrderStateMachineInstance(OrderState.New);
var billing = new BillingStateMachineInstance(BillingState.New);
var shipping = new ShippingStateMachineInstance(ShippingState.New);

var aggregator = new OrderAggregator();

order.Apply(OrderTransition.Create);
billing.Apply(BillingTransition.Authorize);
shipping.Apply(ShippingTransition.PrepareShipping);

var aggregateStatus = aggregator.Evaluate(
[
    (order, order),
    (billing, billing),
    (shipping, shipping)
]);

Console.WriteLine(aggregateStatus.Code);

Choosing Between Stateless and Stateful Models

Stateless machines:

  • simpler
  • easier to persist
  • ideal for event sourcing

Stateful machines:

  • encapsulate state
  • easier imperative usage
  • integrate directly with aggregation

Public API Summary

StateToken � symbolic extensible value for states and events TransitionToken � symbolic extensible value for transitions StateMachine<TState, TTransition> � passive stateless machine IAggregatableStateMachine � opt-in marker for aggregation IStateProvider � exposes state value IStateAggregator � aggregation authority StateAggregator � base class for aggregators AggregateStatus � aggregate-level outcome


License

MIT License (c) 2026 Optima Software

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

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
3.0.1 111 3/12/2026
3.0.0 115 1/17/2026
2.2.0 115 1/17/2026
2.1.0 119 1/12/2026
2.0.0 114 1/11/2026
1.0.0 122 1/9/2026

RELEASENOTES.md