-
Notifications
You must be signed in to change notification settings - Fork 1
State Machines
State Machine is a Behavior type that is build on a concept of UML State Machine.
State Machine consists of:
- Unique name that identifies State Machine Class,
- Set of States that are representing stable configurations of State Machine (current state),
- Set of Transitions that are connecting States and representing the way to change current state of State Machine.
Stateflows State Machine engine supports following features:
States are representing stable configurations of State Machine instance. Transitions that are connecting States are representing rules that must be followed to change active State: Trigger describing an Event that causes the change, Guard that checks if change can happen and Effect that causes side effect of change.
States can define Internal Transitions that can react to incoming Event without changing current States configuration.
States can define Default Transitions which are automaticaly triggered whenever they are available in current States configuration.
All kinds of Transitions are supporting else Transitions to enable developers to model if-else or switch-else scenarios of States flow.
States flow can also be controlled by using Choice and Junction pseudostates.
States can be nested via Composite States and Orthogonal States, creating tree-like structure. Current state of State Machine is represented by tree of States that are currently active.
Orthogonal States have multiple Regions that contain States. States from different Regions can be active at the same time, enabling developers to model independent scenarios within one model - just like CapsLock and NumLock can have independent state in one keyboard.
States that are orthognal to each other can be entered simultanously using Fork and exited simultanously using Join pseudostates.
Transitions can connect any two States, regardless of their nesting scope and relation (except for States located in orthogonal Regions).
Transitions can be triggered by Time Events, which are automaticaly dispatched by Stateflows.
Any State can declare to defer an Event of specific type; if such Event will be sent to State Machine instance when given State is active, Event will be stored for future use - and dispatched immediatelly when it will no longer be deferred by any active State.
Any Exception thrown by State Machine code is sent to it as an Event and can trigger any Transition.
State Machine can embed other Behaviors in its structure, delegating long-running tasks to Actions and Acitivities to be executed outside State Machine instance.
Developer can register a class that implements IStateMachineObserver or IStateMachineInterceptor interface in order to observe the internal flow of State Machine as well as to influence it.
State Machine definition can be versioned, adding new version does not influence instances which are already running.
State Machine definition can be reused and extended by other State Machine.
Let's consider simple example of State Machine that represents generic business object called 'Document'. It has:
- two states, 'New' and 'Confirmed',
- one transition that changes state from 'New' to 'Confirmed', triggered by event 'Confirm'.
This is how it looks in UML:
stateDiagram-v2
[*] --> New
New --> Confirmed : Confirm
Equivalent Stateflows notation of State Machine can be done directly in Program.cs file:
using Stateflows;
using Stateflows.StateMachines;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddStateflows(b => b
.AddStateMachine("Document", b => b
.AddInitialState("New", b => b
.AddTransition<Confirm>("Confirmed")
)
.AddState("Confirmed")
)
);Above example State Machine directly in Program.cs file - it is the simplest way to define it. Yet, for most scenarions it is recommended to define State Machines as separate classes:
using Stateflows.StateMachines;
namespace Example
{
public class Document : IStateMachine
{
public void Build(IStateMachineBuilder builder) => builder
.AddInitialState("New", b => b
.AddTransition<Confirm>("Confirmed")
)
.AddState("Confirmed");
}
}...and then register it in Program.cs file:
using Stateflows;
using Example;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddStateflows(b => b
.AddStateMachine<Document>()
);Type-based definition presented above requires class that implements interface IStateMachine.
Stateflows heavily uses so-called lambda builder pattern to model nested structures. General idea is to have a lambda with fluent interface builder per nesting level.
// not actual method names ;-)
.AddContainer(b => b // 'b' stands for 'builder'
.AddItem(b => b // next level of structure - next lambda builder
.AddSubitem()
)
.AddItem() // lambda builders are often optional in Stateflows
)Such approach is used to define Transitions within States, States within Composite States etc.
State Machine Behavior can be interacted with by sending Events to it. In order to do that, Behavior handle must be located using IStateMachineLocator:
using Stateflows;
using Stateflows.StateMachines;
namespace Example
{
public class DocumentService(IStateMachineLocator locator) // IStateMachineLocator is available via Dependency Injection
{
public Task ConfirmAsync(int documentId)
{
if (locator.TryLocateStateMachine(new StateMachineId("Document", documentId.ToString()), out var document))
{
await document.SendAsync(new Confirm());
}
}
}
}Home page Support Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0. © by Mikołaj Milewski, 2025
Overview
Installation
Behaviors
State Machines
Building blocks
States
State
Composite State
Orthogonal State
Final State
Pseudostates
Choice
Junction
Fork
Join
Transitions
Transition
Default Transition
Internal Transition
Concepts
Evaluation of Transitions
Activities
Building blocks
Nodes
Action Node
Decision Node
Merge Node
Initial Node
Final Node
Input Node
Output Node
Fork Node
Join Node
Accept Event Action Node
Send Event Action Node
Data Store Node
Structured Activity Node
Iterative Activity Node
Parallel Activity Node
Flows
Data Flow
Control Flow
Concepts
Implicit fork and join
Actions