Lite.StateMachine 2.0.0-alpha2

This is a prerelease version of Lite.StateMachine.
dotnet add package Lite.StateMachine --version 2.0.0-alpha2
                    
NuGet\Install-Package Lite.StateMachine -Version 2.0.0-alpha2
                    
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="Lite.StateMachine" Version="2.0.0-alpha2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lite.StateMachine" Version="2.0.0-alpha2" />
                    
Directory.Packages.props
<PackageReference Include="Lite.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 Lite.StateMachine --version 2.0.0-alpha2
                    
#r "nuget: Lite.StateMachine, 2.0.0-alpha2"
                    
#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 Lite.StateMachine@2.0.0-alpha2
                    
#: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=Lite.StateMachine&version=2.0.0-alpha2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Lite.StateMachine&version=2.0.0-alpha2&prerelease
                    
Install as a Cake Tool

Lite State Machine for .NET

Flexible lightweight finite state machine (FSM) for .NET, supporting shared context for passing parameters, composite (sub) states, command states, lazy-loading and thread safe. The library is AOT friendly, cross-platform and optimized for speed for use in enterprise, robotic/industrial systems, and even tiny (mobile) applications.

The Lite State Machine is designed for vertical scaling. Meaning, it can be used for the most basic (tiny) system and beyond medical-grade robotics systems.

Download Lite.StateMachine @ NuGet.org today!

Copyright 2022-2025 Xeno Innovations, Inc. (dba, Suess Labs)<br /> Created by: Damian Suess<br /> Date: 2022-06-07<br />

Usage

Create a state machine by defining the states, transitions, and shared context.

You can define the state machine using either the fluent design pattern or standard line-by-line. Each state is represented by a enum StateId in the following example.

Basic State

// That's it! Just create the state machine, register states, and run it.
var machine = await new StateMachine<StateId>()
  .RegisterState<BasicState1>(StateId.State1, StateId.State2)
  .RegisterState<BasicState2>(StateId.State2, StateId.State3)
  .RegisterState<BasicState3>(StateId.State3)
  .RunAsync(StateId.State1);

// To avoid hung states, you can pass in a timeout value (in milliseconds)
// Useful for robotic systems; fail fast and recover!
var machine = new StateMachine<BasicStateId>();
machine.DefaultStateTimeoutMs = 3000;

Define States:

// Optional Wrapper
public class BaseState : IState<StateId>
{
  public virtual Task OnEntering(Context<StateId> context) => Task.CompletedTask;
  public virtual Task OnEnter(Context<StateId> context) => Task.CompletedTask;
  public virtual Task OnExit(Context<StateId> context) => Task.CompletedTask;
}

public class BasicState1() : IState<StateId>
{
  public async Task OnEnter(Context<BasicStateId> context)
  {
    await Task.Yield(); // Some async work here...
    context.NextState(Result.Ok);
  }
}

public class BasicState2() : IState<StateId>
{
  public Task OnEnter(Context<StateId> context)
  {
    context.NextState(Result.Ok);
    return Task.CompletedTask; // Notice, we did not async/await this method
  }
}

public class BasicState3() : IState<StateId>
{
  public Task OnEnter(Context<StateId> context)
  {
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

Composite States

using Lite.StateMachine;

var ctxProperties = new PropertyBag() { { "CounterKey", 0 } };

// Note the use of generics '<TStateClass>' to strongly-type the state machine
var machine = new StateMachine<CompositeL1StateId>()
  .RegisterState<Composite_State1>(CompositeL1StateId.State1, CompositeL1StateId.State2)

  .RegisterComposite<Composite_State2>(
    stateId: CompositeL1StateId.State2,
    initialChildStateId: CompositeL1StateId.State2_Sub1,
    onSuccess: CompositeL1StateId.State3)

  .RegisterSubState<Composite_State2_Sub1>(
    stateId: CompositeL1StateId.State2_Sub1,
    parentStateId: CompositeL1StateId.State2,
    onSuccess: CompositeL1StateId.State2_Sub2)

  .RegisterSubState<Composite_State2_Sub2>(
    stateId: CompositeL1StateId.State2_Sub2,
    parentStateId: CompositeL1StateId.State2,
    onSuccess: null) // NULL denotes returning to parent state on success

  .RegisterState<Composite_State3>(CompositeL1StateId.State3);

// Optional, pass in starting Context Property
await machine.RunAsync(CompositeL1StateId.State1, ctxProperties);

States are represented by classes that implement the IState interface.

public class Composite_State1() : BaseState
{
  public override Task OnEnter(Context<CompositeL1StateId> context)
  {
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

public class Composite_State2() : BaseState
{
  public override Task OnEnter(Context<CompositeL1StateId> context)
  {
    // Signify we're ready to go to sub-states
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }

  public override Task OnExit(Context<CompositeL1StateId> context)
  {
    // Signify we're ready to go to next state after composite
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

public class Composite_State2_Sub1() : BaseState
{
  public override Task OnEnter(Context<CompositeL1StateId> context)
  {
    context.Parameters.Add("ParameterSubStateEntered", SUCCESS);
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

public class Composite_State2_Sub2() : BaseState
{
  public override Task OnEnter(Context<CompositeL1StateId> context)
  {
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

public class Composite_State3() : BaseState
{
  public override Task OnEnter(Context<CompositeL1StateId> context)
  {
    context.NextState(Result.Ok);
    return Task.CompletedTask;
  }
}

Generate DOT Graph (GraphViz)

var uml = machine.ExportUml(includeSubmachines: true);

Features

  • AOT Friendly - No Reflection, no Linq, etc.
  • Passing parameters between state transitions via Context
  • Types of States
    • Basic Linear State (BaseState)
    • Composite States (CompositeState)
      • Hieratical / Nested Sub-states
      • Similar to Actor/Director model
    • Command States with optional Timeout (CommandState)
      • Uses internal Event Aggregator for sending/receiving messages
      • Allows users to hook to external messaging services (TCP/IP, RabbitMQ, DBus, etc.)
  • State Transition Triggers
    • Transitions are triggered by setting the context's next state result:
    • On Success: context.NextState(Result.Ok);
    • On Error: context.NextState(Result.Error);
    • On Failure: : context.NextState(Result.Failure);
  • State Handlers
    • OnEntering - Initial entry of the state
    • OnEnter - Resting (idle) place for state.
    • OnExit - (Optional) Thrown during transitioning. Used for housekeeping or exiting activity.
    • OnMessage (Optional)
      • Must ensure that code has exited OnMessage before going to the next state.
    • OnTimeout - (Optional) Thrown when the state is auto-transitioning due to timeout exceeded
  • Transition has knowledge of the PreviousState and NextState

References

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.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
2.0.0-alpha2 0 12/30/2025
2.0.0-alpha1 37 12/28/2025

Overhauled framework to include enhanced state definitions for deep sub-state hierarchy, async/await friendly state classes, RegisterState overloads with friendly naming conventions, uses new namespace "Lite.StateMachine".