diff --git a/src/Stateless/StateMachine.Async.cs b/src/Stateless/StateMachine.Async.cs index efe8a9cc..53352441 100644 --- a/src/Stateless/StateMachine.Async.cs +++ b/src/Stateless/StateMachine.Async.cs @@ -236,6 +236,9 @@ async Task InternalFireOneAsync(TTrigger trigger, params object[] args) { var transition = new Transition(source, destination, trigger, args); + // Alert all listeners of state transition + await _onTransitionedInternalEvent.InvokeAsync(transition); + await CurrentRepresentation.InternalActionAsync(transition, args).ConfigureAwait(false); } } diff --git a/src/Stateless/StateMachine.cs b/src/Stateless/StateMachine.cs index 027f7ed0..02367d83 100644 --- a/src/Stateless/StateMachine.cs +++ b/src/Stateless/StateMachine.cs @@ -29,6 +29,7 @@ public partial class StateMachine private readonly Action _stateMutator; private UnhandledTriggerAction _unhandledTriggerAction; private OnTransitionedEvent _onTransitionedEvent; + private OnTransitionedEvent _onTransitionedInternalEvent; private readonly FiringMode _firingMode; private class QueuedTrigger @@ -93,6 +94,7 @@ public StateMachine(TState initialState, FiringMode firingMode) : this() { _unhandledTriggerAction = new UnhandledTriggerAction.Sync(DefaultUnhandledTriggerAction); _onTransitionedEvent = new OnTransitionedEvent(); + _onTransitionedInternalEvent = new OnTransitionedEvent(); } /// @@ -386,7 +388,9 @@ void InternalFireOne(TTrigger trigger, params object[] args) // Internal transitions does not update the current state, but must execute the associated action. var transition = new Transition(source, source, trigger, args); CurrentRepresentation.InternalAction(transition, args); - break; + _onTransitionedInternalEvent.Invoke(transition); + + break; } default: throw new InvalidOperationException("State machine configuration incorrect, no handler for trigger."); @@ -600,5 +604,18 @@ public void OnTransitioned(Action onTransitionAction) if (onTransitionAction == null) throw new ArgumentNullException(nameof(onTransitionAction)); _onTransitionedEvent.Register(onTransitionAction); } + + /// + /// Registers a callback that will be invoked every time the statemachine + /// has an internal transition. + /// + /// + /// The action to execute, accepting the details of the transition + /// + public void OnTransitionedInternal(Action onInternalTransitionAction) + { + if (onInternalTransitionAction == null) throw new ArgumentNullException(nameof(onInternalTransitionAction)); + _onTransitionedInternalEvent.Register(onInternalTransitionAction); + } } }