Beispiel #1
0
        /// <summary>
        /// Gets the current <see cref="WorkflowExecutionFrame"/> for the specified
        /// <see cref="IWorkflowSubject"/>.
        /// </summary>
        /// <param name="workflowSubject">
        /// Workflow subject to get execution frame for.
        /// </param>
        /// <param name="serviceProvider">
        /// Interface to service provider.
        /// </param>
        /// <returns>
        /// A <see cref="WorkflowExecutionFrame"/> object containing the current workflow execution
        /// state information for the specified <see cref="IWorkflowSubject"/>.
        /// objects.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when workflowSubject is null.
        /// </exception>
        /// <exception cref="StateNotFoundException">
        /// Thrown when the current state of the workflow subject cannot be
        /// found in the workflow.
        /// </exception>
        public WorkflowExecutionFrame GetExecutionFrame(IWorkflowSubject workflowSubject, IServiceProvider serviceProvider)
        {
            ///////////////////////////////////////////////////////////////////
            // Check arguments
            if (workflowSubject == null)
            {
                throw new ArgumentNullException("workflowSubject");
            }

            ///////////////////////////////////////////////////////////////////
            // Get the CURRENT state
            var currentStateName = workflowSubject.CurrentState;

            if (string.IsNullOrEmpty(currentStateName))
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var currentState = this.FindStateByName(currentStateName);

            if (currentState == null)
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var nextTransitions = currentState.Transitions.Select(t => new WorkflowTransitionDescriptor()
            {
                TransitionName = t.Name,
                IsAllowed      = t.IsAllowed(serviceProvider, workflowSubject.GetContextObject(serviceProvider))
            });

            return(WorkflowExecutionFrame.Create(workflowSubject, nextTransitions.ToList()));
        }
Beispiel #2
0
        /// <summary>
        /// Determines if the specified transition is allowed
        /// for the workflow subject.
        /// </summary>
        /// <param name="workflowSubject">
        /// Workflow subject to test
        /// </param>
        /// <param name="transitionName">
        /// Transition to test
        /// </param>
        /// <param name="serviceProvider">
        /// Service provider
        /// </param>
        /// <returns>
        /// Returns true if the transition is allowed, otherwise
        /// returns false
        /// </returns>
        /// <remarks>
        /// Checks condition associated with the transition against
        /// the context provided by the workflow subject.
        /// </remarks>
        public WorkflowExecutionResult IsTransitionToAllowed(IWorkflowSubject workflowSubject,
                                                             string transitionName,
                                                             IServiceProvider serviceProvider)
        {
            ///////////////////////////////////////////////////////////////////
            // Get the FROM state
            var currentStateName = workflowSubject.CurrentState;

            if (string.IsNullOrEmpty(currentStateName))
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var fromState = this.FindStateByName(currentStateName);

            if (fromState == null)
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var transition = fromState.GetTransition(transitionName);

            if (transition == null)
            {
                throw new TransitionNotFoundException(fromState, transitionName);
            }
            ///////////////////////////////////////////////////////////////////
            // Check to see if the transition is allowed
            if (!transition.IsAllowed(serviceProvider, workflowSubject.GetContextObject(serviceProvider)))
            {
                return(new WorkflowExecutionResult(WorkflowExecutionResultCode.NotAllowed, string.Format("Transition {0} not allowed {1}", transitionName, transition.ConditionErrorMessage)));
            }

            return(new WorkflowExecutionResult(WorkflowExecutionResultCode.Success));
        }
Beispiel #3
0
        /// <summary>
        /// Gets the collection of allowed transitions that are
        /// available for the given <see cref="IWorkflowSubject"/> from
        /// its <see cref="IWorkflowSubject.CurrentState"/>.
        /// </summary>
        /// <param name="workflowSubject">
        /// Workflow subject to get allowed transitions for.
        /// </param>
        /// <param name="serviceProvider">
        /// Interface to service provider.
        /// </param>
        /// <returns>
        /// A collection of <see cref="WorkflowTransition"/>
        /// objects.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when workflowSubject is null.
        /// </exception>
        /// <exception cref="StateNotFoundException">
        /// Thrown when the current state of the workflow subject cannot be
        /// found in the workflow.
        /// </exception>
        public IEnumerable <WorkflowTransition> GetAllowedTransitions(IWorkflowSubject workflowSubject, IServiceProvider serviceProvider)
        {
            ///////////////////////////////////////////////////////////////////
            // Check arguments
            if (workflowSubject == null)
            {
                throw new ArgumentNullException("workflowSubject");
            }

            ///////////////////////////////////////////////////////////////////
            // Get the CURRENT state
            var currentStateName = workflowSubject.CurrentState;

            if (string.IsNullOrEmpty(currentStateName))
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var currentState = this.FindStateByName(currentStateName);

            if (currentState == null)
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            return(currentState.Transitions
                   .Where(t => t.IsAllowed(serviceProvider, workflowSubject.GetContextObject(serviceProvider))));
        }
Beispiel #4
0
        /// <summary>
        /// Starts execution of an <see cref="IWorkflowSubject"/> object
        /// in this workflow.
        /// </summary>
        /// <param name="workflowSubject">
        /// Workflow subject to start in this workflow.
        /// </param>
        /// <param name="serviceProvider">
        /// Interface to service provider.
        /// </param>
        /// <returns>
        /// Returns a <see cref="WorkflowExecutionResult"/> object
        /// that encapsulates the result of the operation.
        /// </returns>
        /// <remarks>
        /// This method associates the <see cref="IWorkflowSubject"/> with
        /// this workflow, sets the <see cref="IWorkflowSubject.CurrentState"/>
        /// to the <see cref="Workflow.InitialState"/> of this workflow, and
        /// executes the enter action of the initial state.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// Thrown when workflowSubject is null.
        /// </exception>
        /// <exception cref="InitialStateNotFoundException">
        /// Thrown when the workflow has no initial state defined.
        /// </exception>
        public WorkflowExecutionResult Start(IWorkflowSubject workflowSubject, IServiceProvider serviceProvider)
        {
            ///////////////////////////////////////////////////////////////////
            // Check arguments
            if (workflowSubject == null)
            {
                throw new ArgumentNullException("workflowSubject");
            }

            var initialState = this.InitialState;

            if (initialState == null)
            {
                throw new InitialStateNotFoundException();
            }

            ///////////////////////////////////////////////////////////////////
            // Execute EnterAction associated with the INITIAL state
            initialState.ExecuteEnterAction(serviceProvider, workflowSubject.GetContextObject(serviceProvider));

            ///////////////////////////////////////////////////////////////////
            // Assign the name of the workflow to the object
            workflowSubject.WorkflowName = this.FullName;

            ///////////////////////////////////////////////////////////////////
            // Set the current state of the workflow subject
            // to the INITIAL state
            workflowSubject.CurrentState = initialState.Name;

            ///////////////////////////////////////////////////////////////////
            // Invoke OnStarted callback
            workflowSubject.OnStarted(this);

            return(WorkflowExecutionResult.Success);
        }
Beispiel #5
0
        /// <summary>
        /// Transitions the specified workflow subject to a
        /// new state along a given <see cref="WorkflowTransition"/>.
        /// </summary>
        /// <param name="workflowSubject">
        /// Workflow subject to transition to a new state.
        /// </param>
        /// <param name="transitionName">
        /// Name of the <see cref="WorkflowTransition"/> to follow to
        /// the new state.
        /// </param>
        /// <param name="serviceProvider">
        /// Interface to service provider.
        /// </param>
        /// <returns>
        /// Returns a <see cref="WorkflowExecutionResult"/> object
        /// that encapsulates the result of the operation.
        /// </returns>
        /// <remarks>
        /// The transition is only allowed if the
        /// <see cref="WorkflowTransition.Condition"/> evaluates to true.
        /// The <see cref="WorkflowState.ExitAction"/>,
        /// <see cref="WorkflowTransition.Action"/>, and
        /// <see cref="WorkflowState.EnterAction"/> are all fired
        /// along the way.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// Thrown when workflowSubject or transitionName is null.
        /// </exception>
        /// <exception cref="StateNotFoundException">
        /// Thrown when the current state of the workflow subject cannot be
        /// found in the workflow.
        /// </exception>
        /// <exception cref="TransitionNotFoundException">
        /// Thrown when the specified transitionName cannot be found
        /// in the FROM state.
        /// </exception>
        /// <exception cref="ActionFailedException">
        /// Thrown when an action fails exiting a state, transitioning,
        /// or entering a state.
        /// </exception>
        public WorkflowExecutionResult TransitionTo(IWorkflowSubject workflowSubject, string transitionName, IServiceProvider serviceProvider)
        {
            WorkflowExecutionResult res = WorkflowExecutionResult.Success;

            ///////////////////////////////////////////////////////////////////
            // Check arguments
            if (workflowSubject == null)
            {
                throw new ArgumentNullException("workflowSubject");
            }

            if (string.IsNullOrEmpty(transitionName))
            {
                throw new ArgumentNullException("transitionName");
            }

            ///////////////////////////////////////////////////////////////////
            // Get the FROM state
            var currentStateName = workflowSubject.CurrentState;

            if (string.IsNullOrEmpty(currentStateName))
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            var fromState = this.FindStateByName(currentStateName);

            if (fromState == null)
            {
                throw new StateNotFoundException(this, currentStateName);
            }

            ///////////////////////////////////////////////////////////////////
            // Get the transition
            var transition = fromState.GetTransition(transitionName);

            if (transition == null)
            {
                throw new TransitionNotFoundException(fromState, transitionName);
            }

            ///////////////////////////////////////////////////////////////////
            // Check to see if the transition is allowed
            if (!transition.IsAllowed(serviceProvider, workflowSubject.GetContextObject(serviceProvider)))
            {
                return(new WorkflowExecutionResult(
                           WorkflowExecutionResultCode.NotAllowed,
                           string.Format("Transition {0} not allowed {1}", transitionName, transition.ConditionErrorMessage)));
            }

            ///////////////////////////////////////////////////////////////////
            // Get the TO state
            var toState = (from s in this.States
                           where s.Name == transition.ToStateName
                           select s).FirstOrDefault();

            if (toState == null)
            {
                throw new StateNotFoundException(this, transition.ToStateName);
            }

            try
            {
                ///////////////////////////////////////////////////////////////////
                // Fire the pre-transition notification on the workflow subject
                workflowSubject.OnTransitioningTo(this, transition);

                CommandResult actionRes;

                ///////////////////////////////////////////////////////////////////
                // Execute ExitAction associated with the FROM state
                var exitActionTask = fromState.ExecuteExitAction(serviceProvider, workflowSubject.GetContextObject(serviceProvider));
                exitActionTask.RunSynchronously();
                actionRes = exitActionTask.Result;

                if (actionRes.IsSuccess)
                {
                    ///////////////////////////////////////////////////////////////////
                    // Execute Action associated with the transition
                    var transitionActionTask = transition.ExecuteAction(serviceProvider, workflowSubject.GetContextObject(serviceProvider));
                    transitionActionTask.RunSynchronously();
                    actionRes = transitionActionTask.Result;
                }

                if (actionRes.IsSuccess)
                {
                    ///////////////////////////////////////////////////////////////////
                    // Fire the post-transition notification on the workflow subject
                    workflowSubject.OnTransitionedTo(this, transition);
                }

                if (actionRes.IsSuccess)
                {
                    ///////////////////////////////////////////////////////////////////
                    // Set the current state of the workflow subject to the new state
                    workflowSubject.CurrentState = toState.Name;
                }

                if (actionRes.IsSuccess)
                {
                    ///////////////////////////////////////////////////////////////////
                    // Execute EnterAction associated with the TO state
                    var enterActionTask = toState.ExecuteEnterAction(serviceProvider, workflowSubject.GetContextObject(serviceProvider));
                    enterActionTask.RunSynchronously();
                    actionRes = enterActionTask.Result;
                }

                if (!actionRes.IsSuccess)
                {
                    res = new WorkflowExecutionResult(actionRes);
                }
            }
            catch (Exception ex)
            {
                res = new WorkflowExecutionResult(ex);
            }

            return(res);
        }