Language: EN

csharp-stateless

Create state machines in C# with Stateless .NET

The Stateless library is an open-source tool for .NET that allows us to create state machines and workflows in a simple way.

State machines are a modeling methodology that is suitable for solving certain types of problems.

Stateless provides all the features we usually need to generate state machines.

  • Generic states and triggers
  • State hierarchy
  • Actions when entering or leaving states
  • Transitions

In addition to many other non-classic features, but that can be useful in certain cases. The truth is that, in this sense, it is a very complete library.

How to use Stateless .NET

To install “Stateless” in a .NET project, you can use the NuGet package manager. Open the NuGet package manager console and run the command

Install-Package Stateless

Here we have an example of code, taken from the library’s documentation, that simply simulates an ON/OFF control

const string on = "On";
const string off = "Off";
const char space = ' ';

// Instantiate a new state machine in the 'off' state
var onOffSwitch = new StateMachine<string, char>(off);

onOffSwitch.Configure(off).Permit(space, on);
onOffSwitch.Configure(on).Permit(space, off);

Console.WriteLine("Press <space> to toggle the switch. Any other key will exit the program.");

while (true)
{
	Console.WriteLine("Switch is in state: " + onOffSwitch.State);
	var pressed = Console.ReadKey(true).KeyChar;
	
	// Check if user wants to exit
	if (pressed != space) break;

	// Use the Fire method with the trigger as payload to supply the state machine with an event.
	// The state machine will react according to its configuration.
	onOffSwitch.Fire(pressed);
}

In this case, we have a state machine, in which the state is identified by a string, and the trigger by a char.

It only has two states, “On” and “Off”, and a trigger, ’ ’ (space bar).

The ‘configure’ function is used to define the state transitions from On to Off, and vice versa. Both, with the trigger ’ ‘.

Finally, an infinite while loop is used, the keyboard input is checked, and in case it is a space, the transition is fired with the Fire command.

This is a very simple and minimal example to show how it works. For example, a more complex one would be the simulation of the state of a bug tracking tool.

private enum State { Open, Assigned, Deferred, Closed }

private enum Trigger { Assign, Defer, Close }

private readonly StateMachine<State, Trigger> _machine = new StateMachine<State, Trigger>(State.Open);

// ...

// Instantiate a new trigger with a parameter. 
_assignTrigger = _machine.SetTriggerParameters<string>(Trigger.Assign);

// Configure the Open state
_machine.Configure(State.Open)
	.Permit(Trigger.Assign, State.Assigned);

// Configure the Assigned state
_machine.Configure(State.Assigned)
	.SubstateOf(State.Open)
	.OnEntryFrom(_assignTrigger, OnAssigned)  // This is where the TriggerWithParameters is used. Note that the TriggerWithParameters object is used, not something from the enum
	.PermitReentry(Trigger.Assign)
	.Permit(Trigger.Close, State.Closed)
	.Permit(Trigger.Defer, State.Deferred)
	.OnExit(OnDeassigned);

// Configure the Deferred state
_machine.Configure(State.Deferred)
	.OnEntry(() => _assignee = null)
	.Permit(Trigger.Assign, State.Assigned);

In this case, we are using enumerations for both the state and the trigger, which will be the normal way of working with the library.

Next, the transitions between states are defined, and the actions to be performed when entering and leaving the nodes.

As we can see, it is a very complete library for defining state machines. Surely it has all the features that you may ever need in your project. For more information, you can consult the library’s documentation and examples.

Stateless is Open Source, and all the code is available at dotnet-state-machine · GitHub