BusinessRule not Executing

BusinessRule not Executing

Old forum URL: forums.lhotka.net/forums/t/10527.aspx


Phlar posted on Thursday, July 14, 2011

Hi All,

We have constructed a generic class project to house common BusinessRules.  In particular we have a BusinessRule to ensure a To date always follows a From date (from 2 DateTimePicker controls).  I have placed break points on the execute methods but the rule is never fired. 

In the AddBusinessRules we have the following:

BusinessRules.AddRule(

 

new X.Y.BusinessRules.StartDateBeforeEndDate(ActiveFromProperty, ActiveToProperty));

Our generic class project containing the business rule looks like:

namespace X.Y.BusinessRules

{

    [Serializable()]

    public class StartDateBeforeEndDate : BusinessRule

    {

        IBusinessRule _innerRuleStartDate;

        IBusinessRule _innerRuleEndDate;

 

        public StartDateBeforeEndDate(IPropertyInfo startDateProperty, IPropertyInfo endDateProperty)

        {

            _innerRuleStartDate = new InnerStartDateBeforeEndDate(startDateProperty, startDateProperty, endDateProperty)

            {

                AffectedProperties = {endDateProperty}

            };

 

            _innerRuleEndDate = new InnerStartDateBeforeEndDate(endDateProperty, startDateProperty, endDateProperty)

            {

                AffectedProperties = {startDateProperty}

            };

 

            InputProperties = new List<IPropertyInfo>() { startDateProperty, endDateProperty };

 

        }

 

        protected override void Execute(RuleContext context)

        {

            _innerRuleStartDate.Execute(context);

            _innerRuleEndDate.Execute(context);           

        }

 

        private class InnerStartDateBeforeEndDate : BusinessRule

        {

            protected IPropertyInfo StartDateProperty

            {

                get;

                private set;

            }

 

            protected IPropertyInfo EndDateProperty

            {

                get;

                private set;

            }

 

            public InnerStartDateBeforeEndDate(IPropertyInfo primaryProperty, IPropertyInfo startDateProperty, IPropertyInfo endDateProperty)

                : base(primaryProperty)

            {

                if (startDateProperty.Type != typeof(SmartDate) || endDateProperty.Type != typeof(SmartDate))

                {

                    throw new ArgumentException(Resources.StartDateBeforeEndDateResource.ArgumentException);

                }

 

                StartDateProperty = startDateProperty;

                EndDateProperty = endDateProperty;

                InputProperties = new List<IPropertyInfo>() { startDateProperty, endDateProperty };

            }

 

            protected override void Execute(RuleContext context)

            {

                SmartDate start = (SmartDate)context.InputPropertyValues[StartDateProperty];

                SmartDate end = (SmartDate)context.InputPropertyValues[EndDateProperty];

 

                if (start.CompareTo(end) > 0)

                {

                    context.AddErrorResult(string.Format(Resources.StartDateBeforeEndDateResource.RuleMessage, StartDateProperty.FriendlyName, EndDateProperty.FriendlyName));

                }

            }

        }

 

    }

}

Any idea's why this business rule is not firing when the DateTimePicker values are being changed?  The field is being databound to the Value property.

JonnyBee replied on Friday, July 15, 2011

What you are trying to do is not the proper way to create business rules.

From the rule engines perspective you have

So you have a "selector" rule with 2 inner rules (rule chaining). Both inner rules MUST be on the same PrimaryProperty and you must call

context.GetChainedContext

to send the rulecontext to your inner rules. This is described in the Csla 4 EBooks by Rocky.

Your must be aware the the rule engine has absolutely no knowledge of your inner rules - it only knows about the rules that are registered in AddBusinessRules.

Another reason the rule may not be firing is how your properties are defined and databinding (especially for Windows Forms) and the conversion of the value from the UI control to the type as defined in your BO. IE: the value may never be set on the property.

From Csla 4.2 you can create this as just one rule that sets Error/Warn/Info on both properties.

Phlar replied on Friday, July 15, 2011

Thanks JonnyBee.  This class was writen prior to the eBooks being published.  I've had my developer rewrite the code which now executes properly.  I've posted it here just in case anyone else would like a copy:

 

    [Serializable()]

    public class StartDateBeforeEndDate : BusinessRule

    {

        private IPropertyInfo CompareTo { get; set; }

 

        public StartDateBeforeEndDate(IPropertyInfo primaryProperty, IPropertyInfo compareToProperty)

            : base(primaryProperty)

        {

            if (primaryProperty.Type != typeof(SmartDate) || compareToProperty.Type != typeof(SmartDate))

            {

                throw new ArgumentException(Resources.StartDateBeforeEndDateResource.ArgumentException);

            }

 

            CompareTo = compareToProperty;

 

            if (InputProperties == null)

            {

                InputProperties = new List<IPropertyInfo>();

            }

            InputProperties.Add(primaryProperty);

            InputProperties.Add(compareToProperty);

        }

 

        protected override void Execute(RuleContext context)

        {

            SmartDate start = (SmartDate)context.InputPropertyValues[PrimaryProperty];

            SmartDate end = (SmartDate)context.InputPropertyValues[CompareTo];

 

            if (start.CompareTo(end) > 0)

            {

                context.AddErrorResult(string.Format(Resources.StartDateBeforeEndDateResource.RuleMessage, PrimaryProperty.FriendlyName, CompareTo.FriendlyName));

            }

        }

    }

 

Phlar replied on Friday, July 15, 2011

I forgot to include the two lines which invoke the rule:

 

BusinessRules.AddRule(

 

new Dependency(ActiveToProperty, ActiveFromProperty));

BusinessRules.AddRule(

 

new Common.Utilities.BusinessRules.StartDateBeforeEndDate(ActiveFromProperty, ActiveToProperty));

 

JonnyBee replied on Friday, July 15, 2011

You can also find this as a complete ruleset in CslaContrib

LessThan
LessThanOrEqual
GreaterThan
GreaterThanOrEqual

and also all the standard rules in Csla.

These rules also accepts an anonymous method to supply the message from either a custom resource file or a string constant.

Copyright (c) Marimer LLC