public StepsValidator(Func <StepValidatorContext, IValidator <Step> > stepValidatorFn) { CascadeMode = CascadeMode.StopOnFirstFailure; RuleForEach(steps => steps) .SetValidator(c => { var context = new StepValidatorContext { StepIds = c.Select(x => x.Name).ToList() }; return(stepValidatorFn(context)); }); RuleFor(steps => steps) .Custom((steps, context) => { if (steps.All(s => s.Dependencies != null && s.Dependencies.Length > 0)) { context.AddFailure("All the steps have dependencies. None can be executed"); return; } var stepsStatus = steps.ToDictionary(s => s.Name, s => false); var independentSteps = steps.Where(s => s.Dependencies == null || s.Dependencies.Length == 0).ToList(); foreach (var independentStep in independentSteps) { stepsStatus[independentStep.Name] = true; } while (stepsStatus.Any(s => s.Value == false)) { var pendingSteps = stepsStatus.Count(s => s.Value == false); var dependentSteps = steps.Where(s => s.Dependencies != null && s.Dependencies.Length > 0); foreach (var dependentStep in dependentSteps) { var dependencies = dependentStep.Dependencies; if (dependencies.All(d => stepsStatus[d])) { stepsStatus[dependentStep.Name] = true; } } if (pendingSteps == stepsStatus.Count(s => s.Value == false)) { // deadlock break; } } if (stepsStatus.Any(s => s.Value == false)) { context.AddFailure("Steps cannot have cyclic dependencies"); } }); }
public StepValidator(StepValidatorContext validatorContext) { CascadeMode = CascadeMode.Continue; RuleFor(s => s.Name) .NotEmpty() .WithMessage("Step Name must be specified"); RuleFor(s => s.Commands) .Must(c => c != null && c.Count > 0) .WithMessage("A step must have at least one command"); RuleFor(s => s.Dependencies) .Custom((dependencies, context) => { if (dependencies != null && dependencies.Length > 0) { foreach (var dependency in dependencies) { if (!validatorContext.StepIds.Contains(dependency)) { context.AddFailure($"Unknown dependency :{dependency}"); } } } }); }