Example #1
0
        /// <summary>
        /// Determines whether this rule can run the specified context mode.
        /// </summary>
        /// <param name="rule">The rule.</param>
        /// <param name="contextMode">The context mode.</param>
        /// <returns>
        ///     <c>true</c> if this instance [can run rule] the specified context mode; otherwise, <c>false</c>.
        /// </returns>
        internal static bool CanRunRule(IBusinessRule rule, RuleContextModes contextMode)
        {
            // default then just return true
            if (rule.RunMode == RunModes.Default)
            {
                return(true);
            }

            bool canRun = true;

            if ((contextMode & RuleContextModes.AsAffectedPoperty) > 0)
            {
                canRun = canRun & (rule.RunMode & RunModes.DenyAsAffectedProperty) == 0;
            }

            if ((rule.RunMode & RunModes.DenyOnServerSidePortal) > 0)
            {
                canRun = canRun & ApplicationContext.LogicalExecutionLocation != ApplicationContext.LogicalExecutionLocations.Server;
            }

            if ((contextMode & RuleContextModes.CheckRules) > 0)
            {
                canRun = canRun & (rule.RunMode & RunModes.DenyCheckRules) == 0;
            }

            return(canRun);
        }
Example #2
0
 internal RuleContext(Action <RuleContext> completeHandler, LazySingleton <Dictionary <IPropertyInfo, object> > outputPropertyValues, LazySingleton <List <IPropertyInfo> > dirtyProperties, RuleContextModes executeContext)
 {
     _completeHandler      = completeHandler;
     _outputPropertyValues = outputPropertyValues;
     _dirtyProperties      = dirtyProperties;
     ExecuteContext        = executeContext;
 }
Example #3
0
        private List <string> CheckRules(Csla.Core.IPropertyInfo property, RuleContextModes executionContext)
        {
            if (property == null)
            {
                throw new ArgumentNullException("property");
            }

            if (_suppressRuleChecking)
            {
                return(new List <string>());
            }

            var oldRR = RunningRules;

            RunningRules = true;

            var affectedProperties = new List <string>();

            affectedProperties.AddRange(CheckRulesForProperty(property, true, executionContext));

            RunningRules = oldRR;
            if (!RunningRules && !RunningAsyncRules)
            {
                _target.AllRulesComplete();
            }
            return(affectedProperties.Distinct().ToList());
        }
Example #4
0
 internal RuleContext(ApplicationContext applicationContext, Action <IRuleContext> completeHandler, LazySingleton <Dictionary <IPropertyInfo, object> > outputPropertyValues, LazySingleton <List <IPropertyInfo> > dirtyProperties, RuleContextModes executeContext)
 {
     ApplicationContext    = applicationContext ?? throw new ArgumentNullException(nameof(applicationContext));
     ExecuteContext        = executeContext;
     _completeHandler      = completeHandler;
     _outputPropertyValues = outputPropertyValues;
     _dirtyProperties      = dirtyProperties;
 }
Example #5
0
        /// <summary>
        /// Invokes all rules attached at the class level
        /// of the business type.
        /// </summary>
        /// <returns>
        /// Returns a list of property names affected by the invoked rules.
        /// The PropertyChanged event should be raised for each affected
        /// property.
        /// </returns>
        private List <string> CheckObjectRules(RuleContextModes executionContext, bool cascade)
        {
            if (_suppressRuleChecking)
            {
                return(new List <string>());
            }

            var oldRR = RunningRules;

            RunningRules = true;
            var rules = from r in TypeRules.Rules
                        where r.PrimaryProperty == null &&
                        CanRunRule(r, executionContext)
                        orderby r.Priority
                        select r;

            BrokenRules.ClearRules(null);
            // Changed to cascade propertyrule to make async ObjectLevel rules rerun PropertLevel rules.
            var firstResult = RunRules(rules, false, executionContext);

            // rerun property level rules for affected properties
            if (cascade)
            {
                var propertiesToRun = new List <Csla.Core.IPropertyInfo>();
                foreach (var item in rules)
                {
                    if (!item.IsAsync)
                    {
                        foreach (var p in item.AffectedProperties)
                        {
                            propertiesToRun.Add(p);
                        }
                    }
                }
                // run rules for affected properties
                foreach (var item in propertiesToRun.Distinct())
                {
                    var doCascade = false;
                    if (CascadeOnDirtyProperties)
                    {
                        doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
                    }
                    firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
                                                                                  executionContext | RuleContextModes.AsAffectedPoperty));
                }
            }

            RunningRules = oldRR;
            if (!RunningRules && !RunningAsyncRules)
            {
                _target.AllRulesComplete();
            }
            return(firstResult.AffectedProperties.Distinct().ToList());
        }
Example #6
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));
        }
Example #7
0
        /// <summary>
        /// Invokes all rules for a specific property.
        /// </summary>
        /// <param name="property">The property.</param>
        /// <param name="cascade">if set to <c>true</c> [cascade].</param>
        /// <param name="executionContext">The execute context.</param>
        /// <returns></returns>
        private List <string> CheckRulesForProperty(Csla.Core.IPropertyInfo property, bool cascade, RuleContextModes executionContext)
        {
            var rules = from r in TypeRules.Rules
                        where ReferenceEquals(r.PrimaryProperty, property) &&
                        CanRunRule(r, executionContext)
                        orderby r.Priority
                        select r;

            BrokenRules.ClearRules(property);
            var firstResult = RunRules(rules, cascade, executionContext);

            if (CascadeOnDirtyProperties)
            {
                cascade = cascade || firstResult.DirtyProperties.Any();
            }
            if (cascade)
            {
                // get properties affected by all rules
                var propertiesToRun = new List <Csla.Core.IPropertyInfo>();
                foreach (var item in rules)
                {
                    if (!item.IsAsync)
                    {
                        foreach (var p in item.AffectedProperties)
                        {
                            if (!ReferenceEquals(property, p))
                            {
                                propertiesToRun.Add(p);
                            }
                        }
                    }
                }

                // add PrimaryProperty where property is in InputProperties
                var input = from r in TypeRules.Rules
                            where !ReferenceEquals(r.PrimaryProperty, property) &&
                            r.PrimaryProperty != null &&
                            r.InputProperties != null &&
                            r.InputProperties.Contains(property)
                            select r.PrimaryProperty;

                foreach (var p in input)
                {
                    if (!ReferenceEquals(property, p))
                    {
                        propertiesToRun.Add(p);
                    }
                }
                // run rules for affected properties
                foreach (var item in propertiesToRun.Distinct())
                {
                    var doCascade = false;
                    if (CascadeOnDirtyProperties)
                    {
                        doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
                    }
                    firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
                                                                                  executionContext | RuleContextModes.AsAffectedPoperty));
                }
            }

            // always make sure to add PrimaryProperty
            firstResult.AffectedProperties.Add(property.Name);
            return(firstResult.AffectedProperties.Distinct().ToList());
        }
Example #8
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);
    }
Example #9
0
    /// <summary>
    /// Invokes all rules for a specific property.
    /// </summary>
    /// <param name="property">The property.</param>
    /// <param name="cascade">if set to <c>true</c> [cascade].</param>
    /// <param name="executionContext">The execute context.</param>
    /// <returns></returns>
    private List<string> CheckRulesForProperty(Csla.Core.IPropertyInfo property, bool cascade, RuleContextModes executionContext)
    {
      var rules = from r in TypeRules.Rules
                  where ReferenceEquals(r.PrimaryProperty, property)
                    && CanRunRule(r, executionContext)
                  orderby r.Priority
                  select r;

      BrokenRules.ClearRules(property);
      var firstResult = RunRules(rules, cascade, executionContext);
      if (CascadeOnDirtyProperties)
          cascade = cascade || firstResult.DirtyProperties.Any();
      if (cascade)
      {
        // get properties affected by all rules
        var propertiesToRun = new List<Csla.Core.IPropertyInfo>();
        foreach (var item in rules)
          if (!item.IsAsync)
          {
            foreach (var p in item.AffectedProperties)
              if (!ReferenceEquals(property, p))
                propertiesToRun.Add(p);
          }

        // add PrimaryProperty where property is in InputProperties
        var input = from r in TypeRules.Rules
                    where !ReferenceEquals(r.PrimaryProperty, property)
                          && r.PrimaryProperty != null
                          && r.InputProperties != null
                          && r.InputProperties.Contains(property)
                    select r.PrimaryProperty;

        foreach (var p in input)
        {
            if (!ReferenceEquals(property, p))
                propertiesToRun.Add(p);
        }
        // run rules for affected properties
        foreach (var item in propertiesToRun.Distinct())
        {
          var doCascade = false; 
          if (CascadeOnDirtyProperties)
            doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
          firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
                                                               executionContext | RuleContextModes.AsAffectedPoperty));
        }
      }

      // always make sure to add PrimaryProperty
      firstResult.AffectedProperties.Add(property.Name);
      return firstResult.AffectedProperties.Distinct().ToList();
    }
Example #10
0
    /// <summary>
    /// Determines whether this rule can run the specified context mode.
    /// </summary>
    /// <param name="rule">The rule.</param>
    /// <param name="contextMode">The context mode.</param>
    /// <returns>
    /// 	<c>true</c> if this instance [can run rule] the specified context mode; otherwise, <c>false</c>.
    /// </returns>
    internal static bool CanRunRule(IBusinessRule rule, RuleContextModes contextMode)
    {
      // default then just return true
      if (rule.RunMode == RunModes.Default) return true;

      bool canRun = true;

      if ((contextMode & RuleContextModes.AsAffectedPoperty) > 0)
        canRun = canRun & (rule.RunMode & RunModes.DenyAsAffectedProperty) == 0;

      if ((rule.RunMode & RunModes.DenyOnServerSidePortal) > 0) 
        canRun = canRun & ApplicationContext.LogicalExecutionLocation != ApplicationContext.LogicalExecutionLocations.Server;

      if ((contextMode & RuleContextModes.CheckRules) > 0)
        canRun = canRun &  (rule.RunMode & RunModes.DenyCheckRules) == 0;

      return canRun;
    }
Example #11
0
    private  List<string> CheckRules(Csla.Core.IPropertyInfo property, RuleContextModes executionContext)
    {
      if (property == null)
        throw new ArgumentNullException("property");

      if (_suppressRuleChecking)
        return new List<string>();

      var oldRR = RunningRules;
      RunningRules = true;

      var affectedProperties = new List<string>();
      affectedProperties.AddRange(CheckRulesForProperty(property, true, executionContext));

      RunningRules = oldRR;
      if (!RunningRules && !RunningAsyncRules)
        _target.AllRulesComplete();
      return affectedProperties.Distinct().ToList();
    }
Example #12
0
    /// <summary>
    /// Invokes all rules attached at the class level
    /// of the business type.
    /// </summary>
    /// <returns>
    /// Returns a list of property names affected by the invoked rules.
    /// The PropertyChanged event should be raised for each affected
    /// property.
    /// </returns>
    private List<string> CheckObjectRules(RuleContextModes executionContext, bool cascade)
    {
      if (_suppressRuleChecking)
        return new List<string>();
       
      var oldRR = RunningRules;
      RunningRules = true;
      var rules = from r in TypeRules.Rules
                  where r.PrimaryProperty == null
                    && CanRunRule(r, executionContext)
                  orderby r.Priority
                  select r;
      BrokenRules.ClearRules(null);
      // Changed to cascade propertyrule to make async ObjectLevel rules rerun PropertLevel rules.
      var firstResult = RunRules(rules, false, executionContext);

      // rerun property level rules for affected properties 
      if (cascade)
      {
        var propertiesToRun = new List<Csla.Core.IPropertyInfo>();
        foreach (var item in rules)
          if (!item.IsAsync)
          {
            foreach (var p in item.AffectedProperties)
              propertiesToRun.Add(p);
          }
        // run rules for affected properties
        foreach (var item in propertiesToRun.Distinct())
        {
          var doCascade = false;
          if (CascadeOnDirtyProperties)
            doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
          firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
                                                            executionContext | RuleContextModes.AsAffectedPoperty));
        }
      }

      RunningRules = oldRR;
      if (!RunningRules && !RunningAsyncRules)
        _target.AllRulesComplete();
      return firstResult.AffectedProperties.Distinct().ToList();
    }
Example #13
0
 internal RuleContext(Action <RuleContext> completeHandler, RuleContextModes executeContext) : this(completeHandler)
 {
     ExecuteContext = executeContext;
 }
Example #14
0
 internal RuleContext(ApplicationContext applicationContext, Action <IRuleContext> completeHandler, RuleContextModes executeContext)
     : this(applicationContext, completeHandler)
 {
     ApplicationContext = applicationContext;
     ExecuteContext     = executeContext;
 }