CSLA 4X Validation Rules: InputProperties how to deal properly with multiple properties?

CSLA 4X Validation Rules: InputProperties how to deal properly with multiple properties?

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


JCardina posted on Wednesday, March 28, 2012

There is no example in the Ebooks of how to deal with multiple properties in a validation rule I've seen a whole assortment of varying ways to do it in the forums here and now I'm not sure what is correct.

Assuming you have a validation rule for a property that depends on a secondary property, how do you write that rule so that you can take two properties as parameters to the rule, insert both into InputProperties and then retrieve both in Execute so you can compare their values?  (I need to write a rule that checks a start date occurs before an end date)

JonnyBee replied on Wednesday, March 28, 2012

Look at the RuleTutorial sample (Csla 4.3 Samples) or rules on http://cslacontrib.codeplex.com  and http://cslagenfork.codeplex.com

Here's a bite from RuleTutorial - 2.07 CompareFieldsRules:

namespace CompareFieldsRules.Rules
{

  /// <summary>
  /// Validates that primary property is greater than compareToProperty
  /// </summary>
  public class GreaterThan : CommonBusinessRule
  {
    /// <summary>
    /// Gets or sets CompareTo.
    /// </summary>
    private IPropertyInfo CompareTo { getset; }

    /// <summary>
    /// Initializes a new instance of the <see cref="GreaterThan"/> class.
    /// </summary>
    /// <param name="primaryProperty">
    /// The primary property.
    /// </param>
    /// <param name="compareToProperty">
    /// The compare to property.
    /// </param>
    public GreaterThan(IPropertyInfo primaryProperty, IPropertyInfo compareToProperty)
      : base(primaryProperty)
    {
      CompareTo = compareToProperty;
      InputProperties = new List<IPropertyInfo>() { primaryProperty, compareToProperty };
    }

    /// <summary>
    /// Gets the message.
    /// </summary>
    /// <returns>
    /// The get message.
    /// </returns>
    protected override string GetMessage()
    {
      return HasMessageDelegate ? base.GetMessage() : Resources.GreaterThanRule;
    }

    /// <summary>
    /// Does the check for primary propert less than compareTo property
    /// </summary>
    /// <param name="context">
    /// Rule context object.
    /// </param>
    protected override void Execute(RuleContext context)
    {
      var value1 = (IComparable)context.InputPropertyValues[PrimaryProperty];
      var value2 = (IComparable)context.InputPropertyValues[CompareTo];

      if (value1.CompareTo(value2) <= 0)
      {
        context.Results.Add(new RuleResult(this.RuleName, PrimaryProperty, string.Format(GetMessage(), PrimaryProperty.FriendlyName, CompareTo.FriendlyName)) { Severity = this.Severity });
      }
    }
  }
}

Usage:

      BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty));
or
      BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty) 
                            {MessageText ="My own error message {0} must be grater than {1}"});
or
      BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty) 
                            {MessageDelegate = () => Resources.MyOwnTransateableResourseString});
or
      BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty) 
                            {MessageDelegate = () => Resources.MyOwnTransateableResourseString, 
                             Severity = RuleSeverity.Warning});

In this sample you also have GreaterThanOrEqual, LessThan, LessThanOrEqual rules.

JCardina replied on Wednesday, March 28, 2012

Interesting thank you.

I wasn't aware of the rule tutorial stuff, I'll have to look into that further.

On a side note: the private CompareTo property being used to get the property out of InputProperties in Execute seems a bit tortuous. 

Is there a possibility of improving the way property parameters are accessed from within Execute in CSLA?

JonnyBee replied on Wednesday, March 28, 2012

On a general term, you may have more than 2 InputProperties and need to have the key for the property value.

Remember also that the rule exists in only one instance per property. IE: one "singelton" instance per property for all BO instances of that type. 

So I prefer this style with input properties for easy unit testing. See the unit test samples in RuleTutorial.

For more specific rules there's a few updates coming in CSLA 4.5 to use generics when reading properties.

Copyright (c) Marimer LLC