How to encapsulate .NET Stateless state machine - c#

I have a project where there is a mostly linear workflow. I'm attempting to use the .NET Stateless library to act as workflow engine/state machine. The number of examples out there is limited, but I've put together the following code:
private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine;
private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, DateTime> registrationTrigger;
private Patient patient;
public Patient RegisterPatient(DateTime dateOfBirth)
{
configureStateMachine(WorkflowState.Unregistered);
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
logger.Info("State changed to: " + stateMachine.State);
return patient;
}
private void configureStateMachine(WorkflowState state)
{
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(state);
registrationTrigger = stateMachine.SetTriggerParameters<DateTime>(WorkflowTrigger.Register);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (dateOfBirth) => registerPatient(dateOfBirth));
}
private void registerPatient(DateTime dateOfBirth)
{
//Registration code
}
As you can see, I'm using the Stateless Fire() overload that allows me to pass in a trigger. This is so I can have the state machine process business logic, in this case, code to register a new patient.
This all works, but now I'd like to move all the state machine code into another class to encapsulate it and I'm having trouble doing this. The challenges I've had in doing this are:
instantiating a StateMachine object requires you to specify state and State is a readonly property that can only be set at instantiation.
my registrationTrigger has to be instantiated during state machine configuration and also has to be available by the calling class.
How can I overcome these items and encapsulate the state machine code?

There is an article by Scott Hanselman with an example and introduction to a library. Also there few examples available on their GitHub including Bug implementation example mentioned in Scott's article that encapsulates the state machine.
Below is an example of how the state can be extracted from behavior:
public class PatientRegistrationState
{
private StateMachine<WorkflowState, WorkflowTrigger> stateMachine;
private StateMachine<WorkflowState, WorkflowStateTrigger>.TriggerWithParameters<DateTime> registrationTrigger;
public PatientRegistrationState(State initialState = default(State)) {
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(initialState);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (date) => OnPatientRegistered(date));
}
public WorkflowState State => stateMachine.State;
public Action<DateTime> OnPatientRegistered {get; set;} = (date) => { };
// For state changes that do not require parameters.
public void ChangeTo(WorkflowTrigger trigger)
{
stateMachine.Fire<DateTime>(trigger);
}
// For state changes that require parameters.
public void ChangeToRegistered(DateTime dateOfBirth)
{
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
}
// Change to other states that require parameters...
}
public class PatientRegistration
{
private PatientRegistrationState registrationState;
private Patient patient;
public PatientRegistration()
{
registrationState = PatientRegistrationState(WorkflowState.Unregistered)
{
OnPatientRegistered = RegisterPatient;
}
}
public Patient RegisterPatient(DateTime dateOfBirth)
{
registrationState.ChangeToRegistered(dateOfBirth);
logger.Info("State changed to: " + registrationState.State);
return patient;
}
private void RegisterPatient(DateTime dateOfBirth)
{
// Registration code
}
}

This is how I achieved it in my project.
Separated workflow logic to separate class. I had couple of workflows based on one of the flags present in the request object; below is one of the workflow classes:
public class NationalWorkflow : BaseWorkflow
{
public NationalWorkflow(SwiftRequest request) : this(request, Objects.RBDb)
{ }
public NationalWorkflow(SwiftRequest request, RBDbContext dbContext)
{
this.request = request;
this.dbContext = dbContext;
this.ConfigureWorkflow();
}
protected override void ConfigureWorkflow()
{
workflow = new StateMachine<SwiftRequestStatus, SwiftRequestTriggers>(
() => request.SwiftRequestStatus, state => request.SwiftRequestStatus = state);
workflow.OnTransitioned(Transitioned);
workflow.Configure(SwiftRequestStatus.New)
.OnEntry(NotifyRequestCreation)
.Permit(SwiftRequestTriggers.ProcessRequest, SwiftRequestStatus.InProgress);
workflow.Configure(SwiftRequestStatus.InProgress)
.OnEntry(ValidateRequestEligibility)
.Permit(SwiftRequestTriggers.AutoApprove, SwiftRequestStatus.Approved)
.Permit(SwiftRequestTriggers.AdvancedServicesReview, SwiftRequestStatus.PendingAdvancedServices);
.....................
}
Which is triggered from the controller/any other layer:
private static void UpdateRequest(SwiftRequestDTO dtoRequest)
{
var workflow = WorkflowFactory.Get(request);
workflow.UpdateRequest();
}
As mentioned above, I had different workflow rules based on conditions in the request object and hence used a factory pattern WorkflowFactory.Get(request); you may create an instance of your workflow/inject it as desired
And inside the workflow class (BaseWorkflow class in my case), I have exposed the actions:
public void UpdateRequest()
{
using (var trans = this.dbContext.Database.BeginTransaction())
{
this.actionComments = "Updating the request";
this.TryFire(SwiftRequestTriggers.Update);
SaveChanges();
trans.Commit();
}
}
protected void TryFire(SwiftRequestTriggers trigger)
{
if (!workflow.CanFire(trigger))
{
throw new Exception("Cannot fire " + trigger.ToString() + " from state- " + workflow.State);
}
workflow.Fire(trigger);
}

Related

Reflection only successful on first call in Blazor-State-Management

I discovered a weird behavior where I absolutely don't know where it comes from or how to fix it.
The issue arises with the blazor-state management (which is based on the mediator pattern) - library can be found here: https://timewarpengineering.github.io/blazor-state/.
Lets assume we have the following base class for an enumeration:
public abstract class Simple<TSimple> where TSimple: Simple<TSimple>
{
private readonly string _key;
protected Simple(string key)
{
_key = key;
}
public virtual string Key => _key;
public static TSimple Create(string key)
{
var obj = All.SingleOrDefault(e => e.Key == key);
return obj;
}
public static IReadOnlyCollection<TSimple> All => GetAll();
private static IReadOnlyCollection<TSimple> GetAll()
{
var enumerationType = typeof(TSimple);
return enumerationType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(info => enumerationType.IsAssignableFrom(info.FieldType))
.Select(info => info.GetValue(null))
.Cast<TSimple>()
.ToArray();
}
}
And the following enumeration implementation:
public class SimpleImpl : Simple<SimpleImpl>
{
public static readonly SimpleImpl One = new SimpleImpl("Important");
public static readonly SimpleImpl Two = new SimpleImpl("Urgent");
public static readonly SimpleImpl Three = new SimpleImpl("ImportantAndUrgent");
public static readonly SimpleImpl Four = new SimpleImpl("None");
private SimpleImpl(string key) : base(key)
{
}
}
So far so good.
I use this enumeration in a blazor app, where the data is retrieved via gRPC-Web from the backend, is transformed and added to the state.
So the code section of the Index.cshtml looks something like this:
#code
{
private AppState AppState => GetState<AppState>();
protected override async Task OnInitializedAsync()
{
foreach (var simple in new[] {"Important", "Urgent", "ImportantAndUrgent", "None"})
{
await Mediator.Send(new AppState.AddAction(simple));
}
}
This gets handled by the Handler:
public partial class AppState
{
public class AppHandler : ActionHandler<AddAction>
{
private AppState AppState => Store.GetState<AppState>();
public AppHandler(IStore store) : base(store)
{
}
public override async Task<Unit> Handle(AddAction aAction, CancellationToken aCancellationToken)
{
var simple = SimpleImpl.Create(aAction.Simple);
Console.WriteLine(simple == null); // First call false, afterwards true
AppState.Simples.Add(simple); // If I don't add the object to the state, Simple.Create always returns an object
return await Unit.Task;
}
}
}
And here is the problem. On the first try everything works, but if the functions gets called a second time (so my gRPC-Client returns multiple items) simple will always be null. If I remove the AppState.Simples.Add(simple) then it works again.
If I add the following code: Console.WriteLine(string.Join(",", SimpleImpl.All.Select(s => s.Key)); on the first run it prints all the possible values:
Important,Urgent,ImportantAndUrgent,None
On the second run, this:
,Urgent,,
Urgent was in the Dto in the first run. So it seems something to do with how the reference in the List is kept alive (which should not interfer with how the reflection part in Simple works).
Furthermore: in the GetAll() function of Simple everything works fine until the Select(info => .GetValue(null)) The FieldInfo-Property itself holds all 4 options. After GetValue and the cast there is only the last choosen one "alive".
The State-Entity looks like the following:
public partial class AppState : State<AppState>
{
public IList<SimpleImpl> Simples { get; private set; }
public override void Initialize()
{
Simples = new List<SimpleImpl>();
}
}
And the Action of this sample:
public partial class AppState
{
public class AddAction : IAction
{
public AddAction(string simple)
{
Simple = simple;
}
public string Simple { get; }
}
}
This code is running under .NET Core 3.1.
If anybody has a tip where the problem lays I would be very thankful.
Thanks to #steven-t-cramer how helped me on finding the issue.
Basically it all boils down to the Mediator.Send and State-Handling.
In the Blazor-State library a clone is created when one dispatches and handles an action (so you as a developer don't have to take care of that). But exactly this cloning messed up big time here because of the static nature of Simple(basically an enumeration class).
To get around that, the state can implement ICloneable and do this stuff on its own.
A very naive way to do would be that:
public partial class AppState : State<AppState>, ICloneable
{
private List<SimpleImpl> _simples = new List<SimpleImpl>();
public IReadOnlyList<SimpleImpl> Simples => _simples.AsReadOnly();
public override void Initialize()
{
_simples = new List<SimpleImpl>();
}
public object Clone()
{
var state = new AppState { _simples = _simples};
return state;
}
}

Testing UWP Bluetooth Application

I am trying to develop some tests for a Windows 10 UWP application which uses Windows.Devices.Bluetooth.BluetoothLEDevice. I have a plain class that is part of my application which has a private BluetoothLEDevice type field.
class MyDevice
{
private Windows.Devices.Bluetooth.BluetoothLEDevice BluetoothLEDevice;
public string SomeProperty { get; set; }
public MyDevice(Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice)
{
BluetoothLEDevice = bluetoothLEDevice;
var characteristic = BluetoothLEDevice.GetGattService(...)
.GetCharacteristics(...)
.First();
characteristic.ValueChanged += OnValueChanged;
}
// TODO: Write tests for this method
private OnValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
string message = Encoding.ASCII.GetString(args.CharacteristicValue.ToArray());
// Parse `message`
SomeProperty = parsed;
}
...
}
The methods of said class use the events and methods of bluetoothLEDevice, some are private and others are public. How can I test the public methods of MyDevice?
I have tried something like this which I think could work, but I can see that it will take hundreds of lines of code and quite a few extra classes because I would need to implement a lot of stuff in FakeBluetoothLEDevice in orde for it to work properly.
I changed MyDevice to accept a wrapper instead and then create two implementations of the wrapper. One for testing, and the other for real use.
class MyDevice
{
private MyApp.IBluetoothLEDeviceWrapper bluetoothLEDevice;
}
Then in my test I use the fake.
private void ValueChangedEventDataParsingTest()
{
var device = new FakeBluetoothLEDevice();
var myDevice = new MyDevice(device);
device.InvokeValueChanged("this is the value for a fake ValueChangedEvent");
Assert.Equals(probe.SomeProperty, "expected");
}
Are there any frameworks (available for UWP) that would help me achieve what I want? Or even a better approach that would save me some pain?
In stead of focusing on implementation concerns focus on what functionality you want your abstraction to expose. Using your simplified example I was able to replicate it with some refactors to only interact with the desired functionality.
[TestClass]
public class DeviceTests {
[TestMethod]
public void _ValueChangedEventDataParsingTest() {
//Arrange
var message = "message";
var expected = "expected";
var device = new FakeBluetoothLEDevice(message, expected);
var sut = new MyDevice(device);
//Act
device.InvokeValueChanged(message);
//Assert
Assert.AreEqual(expected, sut.SomeProperty);
}
public interface IBlueToothService {
Action<string> ValueChangedHandler { get; set; }
}
public class FakeBluetoothLEDevice : IBlueToothService {
private string message;
private string parsed;
public FakeBluetoothLEDevice(string message, string expected) {
this.message = message;
this.parsed = expected;
}
public Action<string> ValueChangedHandler { get; set; }
public void InvokeValueChanged(string p) {
var handler = ValueChangedHandler ?? delegate { };
if (p == message) {
ValueChangedHandler(parsed);
}
}
}
public class MyDevice {
private IBlueToothService device;
public string SomeProperty { get; set; }
public MyDevice(IBlueToothService device) {
this.device = device;
device.ValueChangedHandler = handler;
}
private void handler(string parsedValue) {
SomeProperty = parsedValue;
}
}
}
Use separation of concerns and move the heavy lifting of implementation concerns behind the actual implementations. It vastly simplifies the consumers of such functionality.
If the concern is to test he parsing functionality then abstract the out into its own concern as well. Don't have classes doing more than they need to (SRP)
private OnValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) {
string message = Encoding.ASCII.GetString(args.CharacteristicValue.ToArray());
// Parse `message`
var parsed = parsingServce.Parse(message);
SomeProperty = parsed;
}
That way the parsing service implementation will only need to be tested for ts core functionality.
But from an abstraction perspective the parser is not needed as a dependency when testing higher level functionality.
I advise reviewing the current design and refactoring it to be more SOLID.

More .net approach for dynamic state machine

I wrote a simple dynamic FSM. Dynamic means the state transitions are dynamic and not static as shown in ConcreteStateB.
namespace FSM_Example
{
using System;
class Program
{
static void Main()
{
var context = new Context(new ConcreteStateA());
context.Run();
Console.Read();
}
}
abstract class State
{
public abstract void Execute(Context context);
}
class ConcreteStateA : State
{
public override void Execute(Context context)
{
context.State = new ConcreteStateB();
}
}
class ConcreteStateB : State
{
public override void Execute(Context context)
{
Console.Write("Input state: ");
string input = Console.ReadLine();
context.State = input == "e" ? null : new ConcreteStateA();
}
}
class Context
{
private State _state;
public Context(State state)
{
State = state;
}
public State State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State: " + _state.GetType().Name);
}
}
public void Run()
{
while (_state != null)
{
_state.Execute(this);
}
}
}
}
This implements a state machine as described in GoF305.
Since I'm new to C# and .net: Are there better approaches archieving this goal using more specific features from .net or C#?
Outcoldman's answer provides numerous great options.
Now, I know that the code below is not a proper FSM according to the pattern, but for very simple implementations it could help you avoid writing a lot of extra subclasses. It's just a matter of deciding the right tool for the job. This one mainly focuses around the use of the Action<T> generic delegate:
public class Context
{
public Action<Context> State { get; internal set; }
public Context(Action<Context> state)
{
State = state;
}
public void Run()
{
while (State != null)
{
State(this);
}
}
}
And have the "state machine" as:
public static class SimpleStateMachine
{
public static void StateA(Context context)
{
context.State = StateB;
}
public static void StateB(Context context)
{
Console.Write("Input state: ");
var input = Console.ReadLine();
context.State = input == "e" ? (Action<Context>)null : StateA;
}
}
And for kicking off the process you'd use:
var context = new Context(SimpleStateMachine.StateA);
context.Run();
Console.Read();
Also, for states that aren't related you can use Lambda expressions as well, such as:
Action<Context> process = context =>
{
//do something
context.State = nextContext =>
{
//something else
nextContext.State = null;
};
};
There are plenty approaches which you can apply, but mostly it depends on the task which you need to achieve.
You can use interface instead of abstract class. In C# you cannot inherit more than one class, so it is always good to not take this option from realization.
interface IState
{
void Handle(Context context);
}
You can use generics, so you can write base interfaces / classes for State pattern once and use it everywhere:
abstract class IState<T>
{
void Handle(T context);
}
Next things depend on what do you want to hide or don't want to hide. For example you can probably hide setter for property State, to make sure that nobody can use outside of your dll, so you can make the setter of this property internal.
You can use Async for State Change, something like
interface IState
{
Task HandleAsync(Context context);
}
class Context
{
// ...
public async Task RunAsync()
{
while (_state != null)
{
await _state.HandleAsync(this);
}
}
}
My bet that somebody already implemented it with Rx

How do I run code before every test run in MSpec?

I'm trying to run some initialization code before a test. I've tried the suggestions in other questions, but it doesn't seem to work. My domain model raises events via the following class:
public static class DomainEvents
{
private static readonly object #lock = new object();
private static Action<IDomainEvent> raiseEvent;
public static void Raise<TEvent>(TEvent #event) where TEvent : class, IDomainEvent
{
// omitted for brevity
}
public static void RegisterEventPublisher(Action<IDomainEvent> eventPublisher)
{
lock (#lock)
{
raiseEvent = eventPublisher;
}
}
}
For testing purposes I would like to capture these events in a static list. What is the best way of doing this?
Update
The problem was caused by the order in which the tests are run (which as Alexander points out below, is not guaranteed). In one of my specs I had registered a mock event publisher. The fact that the spec would often run in different orders meant that a) to begin with I didn't know I had the issue (the "problem" spec always ran last) and b) Once I started having the issue, the number of failing tests would often vary between runs (making it even more confusing).
The lesson learned - clean up any static resources after each context has run. You can do this by implementing ICleanupAfterEveryContextInAssembly.
Maybe I'm misunderstanding the issue, but the basic pattern is:
public class WhenSomeDomainEventIsRaised
{
private IList<IDomainEvent> EventsRaised = new List<IDomainEvent>();
Establish context = () =>
{
// subscribe to events; when raised, add to EventsRaised list
}
}
If you want to do this for all tests or a subset of tests:
public abstract class DomainSpecification
{
protected IList<IDomainEvent> EventsRaised = new List<IDomainEvent>();
Establish context = () =>
{
// subscribe to events; when raised, add to EventsRaised list
}
}
You can have all specs that need this behaviour inherit from this class, and MSpec will take care of running all Establish blocks along the inheritance hierarchy.
This works for me:
using System;
using System.Collections.Generic;
using Machine.Specifications;
namespace AssemblyContextSpecs
{
public static class DomainEvents
{
static readonly object #lock = new object();
static Action<IDomainEvent> raiseEvent;
public static void Raise<TEvent>(TEvent #event) where TEvent : class, IDomainEvent
{
raiseEvent(#event);
}
public static void RegisterEventPublisher(Action<IDomainEvent> eventPublisher)
{
lock (#lock)
{
raiseEvent = eventPublisher;
}
}
}
public interface IDomainEvent
{
}
class FooEvent : IDomainEvent
{
}
public class DomainEventsContext : IAssemblyContext
{
internal static IList<IDomainEvent> Events = new List<IDomainEvent>();
public void OnAssemblyStart()
{
DomainEvents.RegisterEventPublisher(x => Events.Add(x));
}
public void OnAssemblyComplete()
{
}
}
public class When_a_domain_event_is_raised
{
Because of = () => DomainEvents.Raise(new FooEvent());
It should_capture_the_event =
() => DomainEventsContext.Events.ShouldContain(x => x.GetType() == typeof(FooEvent));
}
}
Shouldn't RegisterEventPublisher rather be RegisterEventSubscriber?

State Pattern C# with previous states

I am new to the state pattern implementation in C#, could you provide some info on how you implement it.
I am refactoring a state machine in C# using the state pattern. Currently my state machine contains 5 states and it is only possible to go forward or backward througout the states,i.e. from state 1 you need to go to state 2, 3 and 4 to finally arrive to state 5.
I am able to go forward just doing
mainclass.State = new NextSate();
which creates a new state every time you want to go forward, however, once all of them have been created and/or you want to go backward I would need to go to the same states, not just a new one. How can I do that? Is there any better way to do it simple?
Strictly speaking, if you're implementing the classic GoF State pattern then the State subclasses themselves are responsible for knowing about and performing the State transitions. The holder of the State isn't responsible for managing the transitions and a large part of the intent of the pattern is to encapsulate the state transition behaviour in the State objects and thus for the client to delegate to them. I've introduced a Factory that ensures that there is only ever a single instance of each State subclass to ensure that the same instance is reused when moving back and forth through the states.
public abstract class State
{
protected StateFactory _factory;
protected IStateUser _context;
public State(StateFactory factory, IStateUser context)
{
_factory = factory;
_context = context;
}
protected void TransitionTo<T>(Func<T> creator) where T : State
{
State state = _factory.GetOrCreate<T>(creator);
_context.CurrentState = state;
}
public abstract void MoveNext();
public abstract void MovePrevious();
}
public class State1 : State
{
public State1(StateFactory factory, IStateUser context)
: base(factory, context)
{
}
public override void MoveNext()
{
TransitionTo<State2>(() => new State2(_factory, _context));
}
public override void MovePrevious()
{
throw new InvalidOperationException();
}
}
public class State2 : State
{
public State2(StateFactory factory, IStateUser context)
: base(factory, context)
{
}
public override void MoveNext()
{
TransitionTo<State3>(() => new State3(_factory, _context)); //State 3 is omitted for brevity
}
public override void MovePrevious()
{
TransitionTo<State1>(() => new State1(_factory, _context));
}
}
public interface IStateUser
{
State CurrentState { get; set; }
}
public class Client : IStateUser
{
public Client()
{
var factory = new StateFactory();
var first = new State1(factory, this);
CurrentState = factory.GetOrCreate<State1>(() => first);
}
public void MethodThatCausesTransitionToNextState()
{
CurrentState.MoveNext();
}
public void MethodThatCausesTransitionToPreviousState()
{
CurrentState.MovePrevious();
}
public State CurrentState
{
get;
set;
}
}
public class StateFactory
{
private Dictionary<string, State> _states = new Dictionary<string, State>();
public State GetOrCreate<T>(Func<T> creator) where T : State
{
string typeName = typeof(T).FullName;
if (_states.ContainsKey(typeName))
return _states[typeName];
T state = creator();
_states.Add(typeName, state);
return state;
}
}
Use internal stack to maintain the previous states:
public class MyClass
{
private Stack<State> _states;
private State _currentState;
public void GoToNextState()
{
// If Not last state then
_states.Push(_currentState);
_currentState = new NextState();
}
public void GoToPrevState()
{
// if not the first state
_currentState = _states.Pop();
}
}
if you want to maintain forward and backward states then create additional stack:
public class MyClass
{
private readonly Stack<State> _nextStates = new Stack<State>();
private readonly Stack<State> _prevStates = new Stack<State>();
private State _currentState = new SampleState1();
public State CurrentState { get { return _currentState; } }
public void GoToNextState()
{
if (_currentState.NextState == null)
return;
_prevStates.Push(_currentState);
_currentState = _nextStates.Count > 0 ? _nextStates.Pop() : _currentState.NextState;
}
public void GoToPrevState()
{
// if not the first state
_nextStates.Push(_currentState);
_currentState = _prevStates.Pop();
}
}
Do you have a state manager of some kind? If so, that one could hold the state instances. By decoupling the state transition knowledge from the states themselves, you let the manager decide on the transition. The manager will inspect the state that requested the transition: it determines it is the "step 1" state, and returns (or creates) the "state 2" state.

Categories