ValidationRules.AddRules(delegate, propertyInfo) does not work

ValidationRules.AddRules(delegate, propertyInfo) does not work

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


lmtoy posted on Tuesday, December 14, 2010

Hi, 

 

I have the following code:

protected override void AddBusinessRules()

{

// Do not validate is marked deleted

if (IsDeleted)

return;

 

AddValidationRule(AccountingClientProperty, VoucherLineValidator.HasValidAccountingClient);

AddValidationRule(AccountingPeriodProperty, VoucherLineValidator.HasValidAccountingPeriod);

// will only work for first validation

AddValidationRule(DueDateProperty, VoucherLineValidator.HasValidDueDate);

AddValidationRule(DueDateProperty, DateTimeValidationRules.ValidSmallDateTime);

// This works:

//ValidationRules.AddRule<VoucherLine>(VoucherLineValidator.HasValidDueDate, DueDateProperty);

//ValidationRules.AddRule<VoucherLine>(DateTimeValidationRules.ValidSmallDateTime, DueDateProperty);

}

 

private void AddValidationRule(IPropertyInfo propertyInfo, Func<VoucherLine, RuleArgs, bool> validationFunc)

{

ValidationRules.AddRule<VoucherLine>((target, ruleArgs) =>

{

// Default validation text. Can be overwritten in validation method

ruleArgs.Description = string.Format("{0} {1}", propertyInfo.FriendlyName, Resources.IsRequired);

return validationFunc(target, ruleArgs);

},

propertyInfo

);

}

 

We have a wrapper method for AddRules where we set a default ruleArgs.Description text. This works fine as long as a property has only 1 validation method. For 2 or more it is only the first validation that is handled properly. All though the code does get called... and it returns false... the property stays valid if the first validation was true.

I can only conlude that the problem is that the ValidationRules.AddRules method cannot handle delegates as first parameter. Can somebody else verify or suggest another way of archieving what I want here? 1 place to set a default text. I have many more proerties and that is why I want this, to avoid having to write it in every validation method. 

I tried to add the validation rules outside our wrapper... and the validation worked fine. 

 

 

 

 

JonnyBee replied on Tuesday, December 14, 2010

Hi,

I think you have missed some important points on business rules!!!

1. AddBusinessRules is only called once per Type, even if it is an instance method!!!!  This is where you define Shared validation rules for all instances of your type. These rules should point to a static method (not depending on an instance of an object).

2. Instance rules should be placed in method AddInstanceBusinessRules and added by calling ValidationRules.AddInstanceRule.

AddBusinessRules and AddInstanceRules are both called  from the constructor of your object (seems like you believe this is instance rules and no sense in testing for IsDeleted here). And you should NOT call these methods from your code

3. Csla default rules does NOT use the RuleArgs.Description. They read the description from a resource string (localizable) to support multiple languages.

lmtoy replied on Wednesday, December 15, 2010

Thansk for the reply. 

1. The rules does point to static methods. 

Here is an example:

 

public static bool HasValidAccountingPeriod(VoucherLine target, RuleArgs ruleArgs)
        {
            if (target.AccountingPeriod == null)
            {
                ruleArgs.Description = GetIsRequiredDescription(ruleArgs);
                return false;
            }

            if (target.AccountingPeriod.PeriodFinalized == EC_AccountingPeriodStatus.Closed)
            {
                ruleArgs.Description = Resources.AccountingPeriodIsClosed;
                return false;
            }

            if (target.AccountingPeriod.PeriodVatFinalized == true && target.VatAccount != null)
            {
                ruleArgs.Description = Resources.VatPeriodIsClosed;
                return false;
            }
            return true;
        }

 

2. Ok.. yes IsDeleted was in the wrong place. I have moved this to Validate() method. 

 

Question: when would you use Instance rules?

 

3.This is do not understand? Can you please elaborate.

We have our program in 2 languages so I do pick up text from resources files. And I also want to write spesific messages to what went wrong, see point 1. We do assign friendlyname to property from resources also.

 

JonnyBee replied on Wednesday, December 15, 2010

1. I  consider ruleArgs.Description as an Out parameter from the Rule. 

2. Instance rules no longer exists in Csla 4.x and it was a lagacy from the first versions of CSLA before Type rules were introduced. So if you are not using instance rules then it is better to just forget about them.  The did work nicely for scenarios where you want to load rules dynamically from f.ex a database for a given instance of an object in a given state but there are alternate ways of achieving this with type rules..

3. The Rule engine expects a static method reference in memory to the validation method that must be available for the entire lifetime of the application. I have never tried to use a Func in this part and for my own preference I'd rather set the message inside the rule or use a combination of rules and use Priority to control the sequence/flow. ex.

IMO: The rule method does the checking and should also be responsible for the message that is returned and not trust some external code to have set a default/initial text for the first condition.

In Csla 4.x Rules are now classes and you can now create a rule that f.ex inherits from Required rule and extend with more checks.

Copyright (c) Marimer LLC