Beispiel #1
0
        /// <summary>
        /// Runs the enumerable list of rules.
        /// </summary>
        /// <param name="rules">The rules.</param>
        /// <param name="cascade">if set to <c>true</c> cascade.</param>
        /// <param name="executionContext">The execution context.</param>
        /// <returns></returns>
        private RunRulesResult RunRules(IEnumerable <IBusinessRule> rules, bool cascade, RuleContextModes executionContext)
        {
            var  affectedProperties = new List <string>();
            var  dirtyProperties    = new List <string>();
            bool anyRuleBroken      = false;

            foreach (var rule in rules)
            {
                // implicit short-circuiting
                if (anyRuleBroken && rule.Priority > ProcessThroughPriority)
                {
                    break;
                }
                bool complete = false;
                // set up context
                var context = new RuleContext((r) =>
                {
                    if (r.Rule.IsAsync)
                    {
                        lock (SyncRoot)
                        {
                            // update output values
                            if (r.OutputPropertyValues != null)
                            {
                                foreach (var item in r.OutputPropertyValues)
                                {
                                    // value is changed add to dirtyValues
                                    if (((IManageProperties)_target).LoadPropertyMarkDirty(item.Key, item.Value))
                                    {
                                        r.AddDirtyProperty(item.Key);
                                    }
                                }
                            }
                            // update broken rules list
                            BrokenRules.SetBrokenRules(r.Results, r.OriginPropertyName);

                            // run rules on affected properties for this async rule
                            var affected = new List <string>();
                            if (cascade)
                            {
                                foreach (var item in r.Rule.AffectedProperties.Distinct())
                                {
                                    if (!ReferenceEquals(r.Rule.PrimaryProperty, item))
                                    {
                                        var doCascade = false;
                                        if (CascadeOnDirtyProperties && (r.DirtyProperties != null))
                                        {
                                            doCascade = r.DirtyProperties.Any(p => p.Name == item.Name);
                                        }
                                        affected.AddRange(CheckRulesForProperty(item, doCascade, r.ExecuteContext | RuleContextModes.AsAffectedPoperty));
                                    }
                                }
                            }

                            // mark each property as not busy
                            foreach (var item in r.Rule.AffectedProperties)
                            {
                                BusyProperties.Remove(item);
                                _isBusy = BusyProperties.Count > 0;
                                if (!BusyProperties.Contains(item))
                                {
                                    _target.RuleComplete(item);
                                }
                            }

                            foreach (var property in affected.Distinct())
                            {
                                // property is not in AffectedProperties (already signalled to UI)
                                if (!r.Rule.AffectedProperties.Any(p => p.Name == property))
                                {
                                    _target.RuleComplete(property);
                                }
                            }

                            if (!RunningRules && !RunningAsyncRules)
                            {
                                _target.AllRulesComplete();
                            }
                        }
                    }
                    else // Rule is Sync
                    {
                        // update output values
                        if (r.OutputPropertyValues != null)
                        {
                            foreach (var item in r.OutputPropertyValues)
                            {
                                // value is changed add to dirtyValues
                                if (((IManageProperties)_target).LoadPropertyMarkDirty(item.Key, item.Value))
                                {
                                    r.AddDirtyProperty(item.Key);
                                }
                            }
                        }

                        // update broken rules list
                        if (r.Results != null)
                        {
                            BrokenRules.SetBrokenRules(r.Results, r.OriginPropertyName);

                            // is any rules here broken with severity Error
                            if (r.Results.Any(p => !p.Success && p.Severity == RuleSeverity.Error))
                            {
                                anyRuleBroken = true;
                            }
                        }

                        complete = true;
                    }
                });
                context.Rule = rule;
                if (rule.PrimaryProperty != null)
                {
                    context.OriginPropertyName = rule.PrimaryProperty.Name;
                }
                context.ExecuteContext = executionContext;
                if (!rule.IsAsync || rule.ProvideTargetWhenAsync)
                {
                    context.Target = _target;
                }

                // get input properties
                if (rule.InputProperties != null)
                {
                    var target = (Core.IManageProperties)_target;
                    context.InputPropertyValues = new Dictionary <IPropertyInfo, object>();
                    foreach (var item in rule.InputProperties)
                    {
                        // do not add lazy loaded fields that have no field data.
                        if ((item.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad)
                        {
                            if (target.FieldExists(item))
                            {
                                context.InputPropertyValues.Add(item, target.ReadProperty(item));
                            }
                        }
                        else
                        {
                            context.InputPropertyValues.Add(item, target.ReadProperty(item));
                        }
                    }
                }

                // mark properties busy
                if (rule.IsAsync)
                {
                    lock (SyncRoot)
                    {
                        // mark each property as busy
                        foreach (var item in rule.AffectedProperties)
                        {
                            var alreadyBusy = BusyProperties.Contains(item);
                            BusyProperties.Add(item);
                            _isBusy = true;
                            if (!alreadyBusy)
                            {
                                _target.RuleStart(item);
                            }
                        }
                    }
                }

                // execute (or start executing) rule
                try
                {
                    rule.Execute(context);
                }
                catch (Exception ex)
                {
                    context.AddErrorResult(string.Format("{0}:{1}", rule.RuleName, ex.Message));
                    if (rule.IsAsync)
                    {
                        context.Complete();
                    }
                }

                if (!rule.IsAsync)
                {
                    // process results
                    if (!complete)
                    {
                        context.Complete();
                    }
                    // copy affected property names
                    affectedProperties.AddRange(rule.AffectedProperties.Select(c => c.Name));
                    // copy output property names
                    if (context.OutputPropertyValues != null)
                    {
                        affectedProperties.AddRange(context.OutputPropertyValues.Select(c => c.Key.Name));
                    }
                    // copy dirty properties
                    if (context.DirtyProperties != null)
                    {
                        dirtyProperties.AddRange(context.DirtyProperties.Select(c => c.Name));
                    }

                    if (context.Results != null)
                    {
                        // explicit short-circuiting
                        if (context.Results.Any(r => r.StopProcessing))
                        {
                            break;
                        }
                    }
                }
            }
            // return any synchronous results
            return(new RunRulesResult(affectedProperties, dirtyProperties));
        }