private WorkflowStepCollection ConvertSteps(ICollection <StepSourceV1> source, Type dataType) { var result = new WorkflowStepCollection(); int i = 0; var stack = new Stack <StepSourceV1>(source.Reverse <StepSourceV1>()); var parents = new List <StepSourceV1>(); var compensatables = new List <StepSourceV1>(); while (stack.Count > 0) { var nextStep = stack.Pop(); var stepType = FindType(nextStep.StepType); var containerType = typeof(WorkflowStep <>).MakeGenericType(stepType); var targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); if (nextStep.Saga) { containerType = typeof(SagaContainer <>).MakeGenericType(stepType); targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); } if (!string.IsNullOrEmpty(nextStep.CancelCondition)) { var cancelExprType = typeof(Expression <>).MakeGenericType(typeof(Func <,>).MakeGenericType(dataType, typeof(bool))); var dataParameter = Expression.Parameter(dataType, "data"); var cancelExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter }, typeof(bool), nextStep.CancelCondition); targetStep.CancelCondition = cancelExpr; } targetStep.Id = i; targetStep.Name = nextStep.Name; targetStep.ErrorBehavior = nextStep.ErrorBehavior; targetStep.RetryInterval = nextStep.RetryInterval; targetStep.ExternalId = $"{nextStep.Id}"; AttachInputs(nextStep, dataType, stepType, targetStep); AttachOutputs(nextStep, dataType, stepType, targetStep); if (nextStep.Do != null) { foreach (var branch in nextStep.Do) { foreach (var child in branch.Reverse <StepSourceV1>()) { stack.Push(child); } } if (nextStep.Do.Count > 0) { parents.Add(nextStep); } } if (nextStep.CompensateWith != null) { foreach (var compChild in nextStep.CompensateWith.Reverse <StepSourceV1>()) { stack.Push(compChild); } if (nextStep.CompensateWith.Count > 0) { compensatables.Add(nextStep); } } if (!string.IsNullOrEmpty(nextStep.NextStepId)) { targetStep.Outcomes.Add(new StepOutcome() { ExternalNextStepId = $"{nextStep.NextStepId}" }); } result.Add(targetStep); i++; } foreach (var step in result) { if (result.Any(x => x.ExternalId == step.ExternalId && x.Id != step.Id)) { throw new WorkflowDefinitionLoadException($"Duplicate step Id {step.ExternalId}"); } foreach (var outcome in step.Outcomes) { if (result.All(x => x.ExternalId != outcome.ExternalNextStepId)) { throw new WorkflowDefinitionLoadException($"Cannot find step id {outcome.ExternalNextStepId}"); } outcome.NextStep = result.Single(x => x.ExternalId == outcome.ExternalNextStepId).Id; } } foreach (var parent in parents) { var target = result.Single(x => x.ExternalId == parent.Id); foreach (var branch in parent.Do) { var childTags = branch.Select(x => x.Id).ToList(); target.Children.AddRange(result .Where(x => childTags.Contains(x.ExternalId)) .OrderBy(x => x.Id) .Select(x => x.Id) .Take(1) .ToList()); } } foreach (var item in compensatables) { var target = result.Single(x => x.ExternalId == item.Id); var tag = item.CompensateWith.Select(x => x.Id).FirstOrDefault(); if (tag != null) { var compStep = result.FirstOrDefault(x => x.ExternalId == tag); if (compStep != null) { target.CompensationStepId = compStep.Id; } } } return(result); }
private WorkflowStepCollection ConvertSteps(ICollection <Step> source, Type dataType) { var result = new WorkflowStepCollection(); int i = 0; var stack = new Stack <Step>(source.Reverse()); var parents = new List <Step>(); var compensatables = new List <Step>(); while (stack.Count > 0) { var nextStep = stack.Pop(); var stepType = FindType(nextStep.StepType); var containerType = typeof(WorkflowStep <>).MakeGenericType(stepType); var targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); if (stepType == typeof(CustomStep)) { targetStep.Inputs.Add(new ActionParameter <CustomStep, object>((pStep, pData) => pStep["__custom_step__"] = nextStep.StepType)); } if (nextStep.Saga) { containerType = typeof(SagaContainer <>).MakeGenericType(stepType); targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); } if (!string.IsNullOrEmpty(nextStep.CancelCondition)) { Func <ExpandoObject, bool> cancelFunc = (data) => _scriptHost.EvaluateExpression <bool>(nextStep.CancelCondition, new Dictionary <string, object>() { ["data"] = data, ["environment"] = Environment.GetEnvironmentVariables() }); Expression <Func <ExpandoObject, bool> > cancelExpr = (data) => cancelFunc(data); targetStep.CancelCondition = cancelExpr; } targetStep.Id = i; targetStep.Name = nextStep.Name; targetStep.ErrorBehavior = nextStep.ErrorBehavior; targetStep.RetryInterval = nextStep.RetryInterval; targetStep.ExternalId = $"{nextStep.Id}"; AttachInputs(nextStep, dataType, stepType, targetStep); AttachOutputs(nextStep, dataType, stepType, targetStep); if (nextStep.Do != null) { foreach (var branch in nextStep.Do) { foreach (var child in branch.Reverse <Step>()) { stack.Push(child); } } if (nextStep.Do.Count > 0) { parents.Add(nextStep); } } if (nextStep.CompensateWith != null) { foreach (var compChild in nextStep.CompensateWith.Reverse <Step>()) { stack.Push(compChild); } if (nextStep.CompensateWith.Count > 0) { compensatables.Add(nextStep); } } if (!string.IsNullOrEmpty(nextStep.NextStepId)) { targetStep.Outcomes.Add(new StepOutcome() { ExternalNextStepId = $"{nextStep.NextStepId}" }); } result.Add(targetStep); i++; } foreach (var step in result) { if (result.Any(x => x.ExternalId == step.ExternalId && x.Id != step.Id)) { throw new WorkflowDefinitionLoadException($"Duplicate step Id {step.ExternalId}"); } foreach (var outcome in step.Outcomes) { if (result.All(x => x.ExternalId != outcome.ExternalNextStepId)) { throw new WorkflowDefinitionLoadException($"Cannot find step id {outcome.ExternalNextStepId}"); } outcome.NextStep = result.Single(x => x.ExternalId == outcome.ExternalNextStepId).Id; } } foreach (var parent in parents) { var target = result.Single(x => x.ExternalId == parent.Id); foreach (var branch in parent.Do) { var childTags = branch.Select(x => x.Id).ToList(); target.Children.AddRange(result .Where(x => childTags.Contains(x.ExternalId)) .OrderBy(x => x.Id) .Select(x => x.Id) .Take(1) .ToList()); } } foreach (var item in compensatables) { var target = result.Single(x => x.ExternalId == item.Id); var tag = item.CompensateWith.Select(x => x.Id).FirstOrDefault(); if (tag != null) { var compStep = result.FirstOrDefault(x => x.ExternalId == tag); if (compStep != null) { target.CompensationStepId = compStep.Id; } } } return(result); }