/// <summary> /// Runs the event. /// </summary> /// <param name="context">The context.</param> /// <returns>The async task.</returns> private async Task StateEventRunner(StateMachineContextBase <TState, TTransition, TPayload> context) { try { await this.OnEnter(context); } catch (Exception ex) { if (null != this.faultHandler) { try { this.faultHandler(context, ex); } catch (Exception newEx) { this.stateMachine.FaultStateMachineContext(context, newEx); } } else { this.stateMachine.HandleFault(context, ex); } } finally { context.EndStateOperation(); } }
/// <summary> /// Handle a fault in the state machine. /// </summary> /// <param name="context">The context.</param> /// <param name="ex">The exception.</param> internal void HandleFault(StateMachineContextBase <TState, TTransition, TPayload> context, Exception ex) { if (StateMachineLifetime.Error == context.CurrentLifecycle) { return; } Exception faultReson = ex; if (this.faultHandler != null) { try { // If this just succeeds. then continue. this.faultHandler(context, ex); return; } catch (Exception newEx) { faultReson = newEx; } } this.FaultStateMachineContext(context, faultReson); }
/// <summary> /// Remove the context. /// </summary> /// <param name="context">The context.</param> internal void RemoveContext(StateMachineContextBase <TState, TTransition, TPayload> context) { lock (this.contexts) { this.contexts.Remove(context); } }
/// <summary> /// Begin invoking the transition on the context. /// </summary> /// <param name="transition">The transition.</param> /// <param name="context">The context.</param> public void InvokeTransition(TTransition transition, StateMachineContextBase <TState, TTransition, TPayload> context) { if (false == this.transitions.TryGetValue(transition, out var tranny)) { throw new InvalidOperationException($"The transition {transition} from the state {this.State} does not exist."); } context.BeginTransition(); // We are now transferring. Tranfer responsibility to the transition object. Task.Run(() => tranny.Execute(context)); }
/// <summary> /// Invokes the state entrance. /// </summary> /// <param name="context">The context.</param> public void InvokeEnter(StateMachineContextBase <TState, TTransition, TPayload> context) { context.BeginStateOperation(); if (null != this.OnEnter) { Task.Run(() => this.StateEventRunner(context)); } else { context.EndStateOperation(); } }
/// <summary> /// Execute the inter-transition interceptor. /// </summary> /// <param name="stateMachineContext">The state machine context.</param> /// <returns>An async task.</returns> internal async Task Execute(StateMachineContextBase <TState, TTransition, TPayload> stateMachineContext) { if (true == this.onTransitionDelegate.Any()) { var context = StateMachineTransitionContext.Create(this.startState, this.endState.State, this.Message, this.stateMachine, stateMachineContext.Payload); await Task.WhenAll(this.onTransitionDelegate.Select(d => this.HandlerExecutor(d, context))); } if (StateMachineLifetime.Error == stateMachineContext.CurrentLifecycle) { return; } // We can continue on the same thread for the executing the next state. stateMachineContext.SetState(this.endState); // Fire of the state entrance. this.endState.InvokeEnter(stateMachineContext); }
/// <summary> /// Fault the state machine context. /// </summary> /// <param name="context">The context.</param> /// <param name="ex">The exception.</param> internal void FaultStateMachineContext(StateMachineContextBase <TState, TTransition, TPayload> context, Exception ex) { this.RemoveContext(context); context.Fault(); }