-
Notifications
You must be signed in to change notification settings - Fork 0
Basic StateMachine (Intro)
Creating states can be as easy or as complex as you intend it to be. Using Lite.StateMachine follows to KISS principals so that you can quickly execute your operation(s) and move along, while offering flexibility in the framework for your unique projects.
Let's start with a basic state machine, and explain the parts as we go.
public enum StateId
{
State1,
State2,
State3,
}
var machine = new StateMachine();
machine.RegisterState(StateId.State1, StateId.State2);
machine.RegisterState(StateId.State2, StateId.State3);
machine.RegisterState(StateId.State3);
await machine.RunAsync();| Name | Type | Description |
|---|---|---|
| [State | IState |
Basic state that can perform an operation or just move along. |
| Composite | IState |
A "parent" state which contains sub-states. The states can be any of these 3 types of states. |
| Command | ICommand |
A state which sends a message and expects a response. The response arrives in the OnMessage method. If it is not received in time (default 3 seconds), it will trigger the OnTimeout method. |
Result.Ok;
Result.Error;
Result.Failure;As of v2.3, you can use AddContext(...) method to pre-load Properties and Errors into the Context. The design change removed the ability to pass in the PropertyBag parameters via the RunAsync(..) method.
v2.2.1 and before, use,
RunAsync(TStateId, properties, errors);for passing the data into the Context.
// Context properties that you want to start out with
var ctxProperties = new PropertyBag()
{
{ ParameterType.Counter, 0 },
{ ParameterType.TestExecutionOrder, true },
};
var machine = await new StateMachine<StateId>()
.RegisterState<BasicState1>(StateId.State1, StateId.State2)
.RegisterState<BasicState2>(StateId.State2, StateId.State3)
.RegisterState<BasicState3>(StateId.State3)
.AddContext(ctxProperties)
.RunAsync(BasicStateId.State1, cancellationToken: TestContext.CancellationToken);The Lite.StateMachine offers the flexibility for any Dependency Injection (DI) framework to plug-into it, so that you can consume other classes/services via each state's constructor.
Most notable container systems include:
- Microsoft.Extensions.DependencyInjection
- DryIoc
- AutoFac
- (and more!)
Need help picking a container, check out these statistics (source)!
| Method | Mean | Error | StdDev | Median |
|---|---|---|---|---|
| DryIoc | 65.70 us | 1.309 us | 2.553 us | 64.46 us |
| DryIoc_MsDI | 97.96 us | 1.959 us | 4.382 us | 96.59 us |
| MsDI | 81.25 us | 1.624 us | 4.686 us | 82.73 us |
| Autofac | 323.50 us | 6.408 us | 8.555 us | 320.06 us |
| Autofac_MsDI | 367.96 us | 7.324 us | 14.111 us | 362.58 us |
| Lamar_MsDI | 3,643.30 us | 56.678 us | 55.666 us | 3,630.33 us |
| Grace | 13,870.26 us | 282.593 us | 824.337 us | 13,837.66 us |
| Grace_MsDI | 17,079.41 us | 318.034 us | 326.598 us | 17,025.77 us |
| Name | Description |
|---|---|
DefaultStateTimeoutMs |
Default value Timeout.Infinite
|
DefaultCommandTimeoutMs |
Default 3000 ms (3 sec) |
The Context is used for passing data from one state to the next. The Context has 2 core properties Parameters and ErrorStack which the user can populate and carry along to the other states for passing data.
The StateMachine has a property named, IsContextPersisted, which determines the lifetime of the parameters (default = true). Meaning, whether or not the keys will be garbage collected by StateMachine after transiting through the hierarchy of Composite states. When disabled (false), keys added to Parameters and ErrorStack during Composite state's OnEntering will remain for the lifetime of that level's hierarchy.
Read more about how the Context works in its own section.
The Event Aggregator is used by the Command states as a built-in mechanism for passing messages internally to the application.
Read more about the Event Aggregator for how to use it and its use-cases.