/// <summary> /// Returns the iterator for <see cref="WorkflowBase.GetEnumerator()" />. /// </summary> /// <param name="obj">The underlying object.</param> /// <param name="contractName">The name of the contract.</param> /// <returns>The iterator.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="obj" /> is <see langword="null" />. /// </exception> protected IEnumerable <WorkflowFunc> GetFunctionIterator(object obj, IEnumerable <char> contractName) { if (obj == null) { throw new ArgumentNullException("obj"); } string contract = WorkflowAttributeBase.ParseContractName(contractName); Type type = obj.GetType(); IEnumerable <MethodInfo> allMethods = GetMethodsByType(type); List <Exception> occuredErrors = new List <Exception>(); // find start method MethodInfo currentMethod = null; { IEnumerable <MethodInfo> methodsWithAttribs = CollectionHelper.Where(allMethods, delegate(MethodInfo method) { // search for 'ReceiveNotificationFromAttribute' object[] attribs = method.GetCustomAttributes(typeof(global::MarcelJoachimKloubert.CLRToolbox.Execution.Workflows.WorkflowStartAttribute), true); // strong typed sequence IEnumerable <WorkflowStartAttribute> wfStartAttribs = CollectionHelper.OfType <WorkflowStartAttribute>(attribs); // filter by contract name IEnumerable <WorkflowStartAttribute> wfStartAttribForMethod = CollectionHelper.Where(wfStartAttribs, delegate(WorkflowStartAttribute a) { return(a.Contract == contract); }); return(CollectionHelper.Any(wfStartAttribForMethod)); }); currentMethod = CollectionHelper.SingleOrDefault(methodsWithAttribs); } IDictionary <string, object> execVars = this.CreateVarStorage(); bool hasBeenCanceled = false; long index = -1; IReadOnlyDictionary <string, object> previousVars = null; object result = null; object syncRoot = new object(); bool throwErrors = true; while ((hasBeenCanceled == false) && (currentMethod != null)) { yield return(delegate(object[] args) { SimpleWorkflowExecutionContext ctx = new SimpleWorkflowExecutionContext(); ctx.Cancel = false; ctx.ContinueOnError = false; ctx.ExecutionArguments = new TMReadOnlyList <object>(args ?? new object[] { null }); ctx.ExecutionVars = execVars; ctx.HasBeenCanceled = hasBeenCanceled; ctx.Index = ++index; ctx.NextVars = this.CreateVarStorage(); ctx.PreviousVars = previousVars; ctx.Result = result; ctx.SyncRoot = syncRoot; ctx.ThrowErrors = throwErrors; ctx.Workflow = this; ctx.WorkflowVars = this.Vars; // first try to find method for next step MethodInfo nextMethod = null; { // search for 'NextWorkflowStepAttribute' object[] attribs = currentMethod.GetCustomAttributes(typeof(global::MarcelJoachimKloubert.CLRToolbox.Execution.Workflows.NextWorkflowStepAttribute), true); // strong typed sequence IEnumerable <NextWorkflowStepAttribute> nextStepAttribs = CollectionHelper.OfType <NextWorkflowStepAttribute>(attribs); // filter by contract name NextWorkflowStepAttribute nextStep = CollectionHelper.SingleOrDefault(nextStepAttribs, delegate(NextWorkflowStepAttribute a) { return a.Contract == contract; }); if (nextStep != null) { IEnumerable <MethodInfo> nextMethods = CollectionHelper.Where(allMethods, delegate(MethodInfo m) { return m.Name == nextStep.Member; }); // first: try find with parameter nextMethod = CollectionHelper.SingleOrDefault(nextMethods, delegate(MethodInfo m) { return m.GetParameters().Length > 0; }); if (nextMethod == null) { // first: now find WITHOUT parameter nextMethod = CollectionHelper.Single(nextMethods, delegate(MethodInfo m) { return m.GetParameters().Length < 1; }); } } } // execution InvokeWorkflowMethod(obj, currentMethod, ctx, occuredErrors); WorkflowActionNoState nextAction = ctx.Next; if (nextAction == null) { currentMethod = nextMethod; } else { obj = nextAction.Target; currentMethod = nextAction.Method; type = currentMethod.ReflectedType; allMethods = GetMethodsByType(type); } previousVars = new TMReadOnlyDictionary <string, object>(ctx.NextVars); throwErrors = ctx.ThrowErrors; if (ctx.Cancel) { hasBeenCanceled = true; ctx.HasBeenCanceled = hasBeenCanceled; } return ctx; }); } if (throwErrors && (occuredErrors.Count > 0)) { throw new AggregateException(occuredErrors); } }
// Protected Methods (1) /// <summary> /// Returns the iterator for <see cref="WorkflowBase.GetEnumerator()" />. /// </summary> /// <typeparam name="S">Type of the state object.</typeparam> /// <param name="startAction">The start action.</param> /// <param name="actionStateFactory">The function that provides the state object for <paramref name="startAction" />.</param> /// <returns>The iterator.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="startAction" /> and/or <paramref name="actionStateFactory" /> are <see langword="null" />. /// </exception> protected IEnumerable <WorkflowFunc> GetFunctionIterator <S>(WorkflowAction <S> startAction, Func <long, S> actionStateFactory) { if (startAction == null) { throw new ArgumentNullException("startAction"); } if (actionStateFactory == null) { throw new ArgumentNullException("actionStateFactory"); } List <Exception> occuredErrors = new List <Exception>(); WorkflowAction <S> currentAction = startAction; IDictionary <string, object> execVars = this.CreateVarStorage(); bool hasBeenCanceled = false; long index = -1; IReadOnlyDictionary <string, object> previousVars = null; object result = null; object syncRoot = new object(); bool throwErrors = true; while ((hasBeenCanceled == false) && (currentAction != null)) { yield return(delegate(object[] args) { SimpleWorkflowExecutionContext <S> ctx = new SimpleWorkflowExecutionContext <S>(); ctx.Cancel = false; ctx.ContinueOnError = false; ctx.ExecutionArguments = new TMReadOnlyList <object>(args ?? new object[] { null }); ctx.ExecutionVars = execVars; ctx.HasBeenCanceled = hasBeenCanceled; ctx.Index = ++index; ctx.Next = null; ctx.NextVars = this.CreateVarStorage(); ctx.PreviousVars = previousVars; ctx.Result = result; ctx.State = actionStateFactory(ctx.Index); ctx.SyncRoot = syncRoot; ctx.ThrowErrors = throwErrors; ctx.Workflow = this; ctx.WorkflowVars = this.Vars; // execution try { currentAction(ctx); result = ctx.Result; } catch (Exception ex) { occuredErrors.Add(ex); if (ctx.ContinueOnError == false) { throw; } } previousVars = new TMReadOnlyDictionary <string, object>(ctx.NextVars); throwErrors = ctx.ThrowErrors; currentAction = ((IWorkflowExecutionContext <S>)ctx).Next; if (ctx.Cancel) { hasBeenCanceled = true; ctx.HasBeenCanceled = hasBeenCanceled; } return ctx; }); } if (throwErrors && (occuredErrors.Count > 0)) { throw new AggregateException(occuredErrors); } }