Conditional Validation

Conditional Validation

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


Wbmstrmjb posted on Monday, November 16, 2009

How do you guys choose to implement conditional validation rules? Are business rules even used as validation rules?

Let's say you have a BO with Name, Zipcode, and Status. Name is required in the DB, so obviously a StringRequired is one rule that is always there.

But let's say a business rule is that if you change Status to "X", Zipcode is required. You can add a custom rule that checks Status and Zipcode and returns true/false accordingly.

Is this appropriate or should there be another method of implementing the rule that is not a "validation rule" ie an Exception or some other catch when they try to set Status to "X" without having a Zipcode?

Thanks,
Mike

rsbaker0 replied on Monday, November 16, 2009

I think conditional rules are fine (and in fact the ability to have conditions that bypass rules entirely is why instance business rules are almost never needed anymore).

Incidentally, you can even call one rule method from another, so (for example) in your dependency between status and zip code above you could conditionaly invoke the StringRequired rule method from within your hypothetical StatusMayRequireZipCode rule.

Fintanv replied on Tuesday, November 17, 2009

rsbaker0:
Incidentally, you can even call one rule method from another, so (for example) in your dependency between status and zip code above you could conditionaly invoke the StringRequired rule method from within your hypothetical StatusMayRequireZipCode rule.

I also use this technique.  Works quite nicely.

JonnyBee replied on Tuesday, November 17, 2009

Hi,

If these rules can be generalized I like to create my own rule that does a simple shortcut, uses a custom RuleArgs or is based on an interface.

Ie: If a field should only be validated when the user is allowed to write I have a rule that says StopIfNotCanWrite. In a similar way you could also write a generic rule that says StopIfFieldEquals / StopIfFieldIsNotEqual and create a generic RuleArgs to contain both propertyName and a value. And finally combine this with RulePriority to control the sequence of validation.

I also override CanReadProperty and CanWriteProperty (AuthorizationRules)  to enable/disable properties based on my BusinessRules. This also allows me to make the UI a slave of my BO by using PropertyStatus (WPF/SL) or ReadWriteAuthorzation (WinForms).

Troncho replied on Tuesday, October 30, 2012

Hi Jonny,

I'm trying to write code according with your interesting idea of coupling a "StopIfNotCanWrite" rule with CanWriteProperty(..) authorization method.

What gets me confused is that if I declare a StopIfNotCanWrite rule, and AddRule(StopIfNotCanWrite, prop, 0) (with priority 0), and the rest of the rules regarding the same "prop" with priority 1, in order to short circuit the Validation Rules Manager, I must make StopIfNotCanWrite  short circuit the Rules Manager and then return "false". That will leave my BO in an invalid state (exactly the opposite of what I want to accomplish). Or when I short circuit the StopIfNotCanWrite rule, I should also return "true" and inform of the writing capabilities via a custom RuleArgs?

Could you please provide a short example of this behavior?

Thanks!

Troncho

JonnyBee replied on Tuesday, October 30, 2012

Look at the CSLA 3.x addon rules here:

https://cslacontrib.svn.codeplex.com/svn/branches/2010.11.001/MyCsla/3-6-3-N2/MyCsla/Validation/MyCommonRules.cs

The StopIfNotCanWrite rule should look like this (included in the link above):

    /// <summary>
    /// Rule indicating whether the user is authorized
    /// to change the property value.
    /// Will always be silent and never set rule to broken.
    /// </summary>
    /// <param name="target">Target object.</param>
    /// <param name="e">Rule arguments.</param>
    /// <returns>true</returns>
    /// <remarks>
    /// Combine this property with short-circuiting to
    /// prevent evaluation of other rules in the case
    /// that the user isn't allowed to change the value.
    /// </remarks>
    public static bool StopIfNotCanWrite(object target, RuleArgs e)
    {
      bool isAuthorized = true;
 
      var business = target as BusinessBase;
      if (business != null && !string.IsNullOrEmpty(e.PropertyName))
        isAuthorized = business.CanWriteProperty(e.PropertyName);
 
      if (!isAuthorized)
      {
        e.StopProcessing = true;
      }
 
      // rule should always return true (be silent) but will stop processing
      // if user cannot modify the value.
      return true;
    }

And I would typically always add this rule with Priority = -1  as this can be combined with DataAnnotationRules that are always added with Priority = 0 and unless specified rules is added with default Priority = 0.

Troncho replied on Wednesday, October 31, 2012

Ok, now I get it Big Smile

It's the rule that check on the "CanWriteProperty(..)", not the other way round.

This is much simpler than I was elaborating on my mind. I was thinking about inheriting RuleArgs to send some in/out info "from" the "CanWriteProperty()" and make the validation rule return some special ResultRuleArgs value to CanWriteProperty() in order to check if the property being evaluated is writeable.

Thanks also on the (-1) priority advice on this special rule hookup. You're right about DataAnnotations (I completely forgot about them in this case...).

And finally thanks for the link to the codeplex project. I'll check it out right now.

As usual, Jonny, your contribution is highly appreciated Big Smile

Thanks,

Troncho

Troncho replied on Wednesday, October 31, 2012

Just took the last whitespace from (%20) from the link you sent me, so it doesnt fail:

https://cslacontrib.svn.codeplex.com/svn/branches/2010.11.001/MyCsla/3-6-3-N2/MyCsla/Validation/MyCommonRules.cs

Troncho replied on Friday, November 02, 2012

Jonny, can I possibly enter directly to the source Codeplex project?

Thanx,

Troncho

JonnyBee replied on Friday, November 02, 2012

yes, you can download all the source from the Source tab.

Troncho replied on Friday, November 02, 2012

I've downloaded file by file of the "3-6-3-N2" project. But I don't see a "source tab".

I entered "www.codeplex.com" with my user and I don't seem to find the project either.

Is there any special link I should address?

Thanx,

Troncho

Troncho replied on Friday, November 02, 2012

BTW, the StopIfNotCanWrite rule works PERFECT! Thanks again!

JonnyBee replied on Friday, November 02, 2012

Goto this page and then select the download button:

http://cslacontrib.codeplex.com/SourceControl/changeset/view/100173

 

Troncho replied on Friday, November 09, 2012

Thanks!

Copyright (c) Marimer LLC