/// <summary>
 /// The item to add to the current collection.
 /// Add the specified state.
 /// </summary>
 /// <param name="state">State.</param>
 public void Add(WorkflowState <T, TContext> state)
 {
     Add(state.Id, state);
 }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Autoflow.WorkflowEngine{T,TContext}"/> class.
        /// </summary>
        /// <param name="workflowDefinition"></param>
        /// <param name="currentState"></param>
        /// <param name="workflowContext"></param>
        public WorkflowEngine(WorkflowDefinition <T, TContext> workflowDefinition,
                              WorkflowState <T, TContext> currentState,
                              TContext workflowContext)
        {
            Guard.ArgumentIsNotNull(workflowDefinition, nameof(workflowDefinition));

            _onTransitionedEvent = new OnWorkflowTransitionedEvent <T, TContext>();
            _workflowContext     = workflowContext;

            _workflowDefinition = workflowDefinition;
            CurrentState        = currentState ?? workflowDefinition.Transitions.First().FromState;
            _stateMachine       = new StateMachine <WorkflowState <T, TContext>, WorkflowTrigger <T> >(() => CurrentState, s => CurrentState = s);

            //  Get a distinct list of states with a trigger from state configuration
            //  "State => Trigger => TargetState
            var states = workflowDefinition.Transitions.AsQueryable()
                         .Select(x => x.FromState)
                         .Distinct()
                         .Select(x => x)
                         .ToList();

            //  Assign triggers to states
            foreach (var state in states)
            {
                var triggers = workflowDefinition.Transitions.AsQueryable()
                               .Where(config => config.FromState == state)
                               .Select(config => new
                {
                    Trigger        = config.TriggeredBy,
                    TargetState    = config.ToState,
                    GuardCondition = config.GuardCondition,
                    IsReentrant    = config.IsReentry
                })
                               .ToList();

                var stateConfig = _stateMachine.Configure(state);

                foreach (var trig in triggers)
                {
                    if (trig.GuardCondition == null)
                    {
                        if (trig.IsReentrant)
                        {
                            stateConfig.PermitReentry(trig.Trigger);
                        }
                        else
                        {
                            if (trig.Trigger != null)
                            {
                                stateConfig.Permit(trig?.Trigger, trig?.TargetState);
                            }
                        }
                    }
                    else
                    {
                        if (trig.Trigger != null)
                        {
                            stateConfig.PermitIf(trig?.Trigger, trig?.TargetState, ConditionalGuard(trig?.GuardCondition));
                        }
                    }
                }

                //actions
                //var actions = workflowDefinition.States.Where();

                if (state.SuperState != null)
                {
                    stateConfig.SubstateOf(state.SuperState);
                }

                if (state.EntryAction != null)
                {
                    stateConfig.OnEntry(t => ExecuteAction(t, state.EntryAction));
                }

                if (state.ExitAction != null)
                {
                    stateConfig.OnExit(t => ExecuteAction(t, state.ExitAction));
                }
            }
            // Handle exceptions
            _stateMachine.OnUnhandledTrigger(OnUnhandledTrigger);

            // For all the state transitions
            _stateMachine.OnTransitioned(OnTransitionAction);
        }
예제 #3
0
 /// <summary>
 /// Provides entry point to the transitions, can be used for logging
 /// </summary>
 /// <param name="source"></param>
 /// <param name="destination"></param>
 /// <param name="trigger"></param>
 /// <param name="reentery"></param>
 public virtual void WorkflowEngine_OnStateTransition(WorkflowState <string, T> source,
                                                      WorkflowState <string, T> destination,
                                                      WorkflowTrigger <string> trigger, bool reentery)
 {
 }
예제 #4
0
 /// <summary>
 /// Allows for the un-handled triggers to be tracked
 /// </summary>
 /// <param name="state"></param>
 /// <param name="trigger"></param>
 protected virtual void OnUnhandledTrigger(WorkflowState <T, TContext> state, WorkflowTrigger <T> trigger)
 {
     OnTriggerUnhandled?.Invoke(state, trigger);
 }