We are using CSLA 3.8.x and want to build some validation rules that configure some default values whenever a property has changed. We are using validation rules as has been suggested on this forum, so to minimize the amount of code that goes into the setter methods in our properties.
However, this causes the problem that when we run the validation rules that these rules also fire and change values that we don't want changed. An example of this is on an invoice, whenver you select a product we set the default description, price, location, etc for that line. However, when loading the values from the database, we obviously want to check QuantityOnHand figures and other rules but don't want to reset any changes the user has made to the description, price, location, etc fields previously.
We have thought of some solutions are would like the communities opinon on what would be best practice:
I'm very intestered in what others have done within the framework, because this cannot be a unique situation.
There are a couple general solutions I think you should consider.
First, rules can (and should) be smart. If a rule should only operate on the object when the object is in a certain state, then the rule should check for that state. You are describing a scenario where the object is in various states (loading data, interacting with user, saving data), and there's absolutely nothing wrong with making your rules smart enough to act (or not act) in each state.
Second, you can use explicit short circuiting to block higher priority rules from running. This isn't as neat as having smart rules, but it can solve some simpler scenarios. Create a rule that checks the object state, and in some state(s) it short circuits rules. Put this at Priority 1 (or something), and put all optional rules at Priority 2.
The rules system in 2.1-3.8 isn't as powerful as the CSLA 4 rules system, and some of the enhancements in CSLA 4 are designed to simplify your type of scenario. But even in CSLA 4, the idea of smart rules applies.
I'm all for smart rules, and that was a solution that was suggested internally. Where we have a property that marks the object to be in a certain state, in which all rules would need to check for and if in that state then bypass the rule that changes / sets default values. We would then have to ensure that property was set before call CheckRules() and then resetting it afterwards we wanted this behaviour.
The second option will not work as the rules which load defaults are expected to run at priority zero and all other rules at priority 1+. Some of the priority 1 rules, expect that the other methods have been run and certain defaults loaded. We don't want every rule to have to check or load certain data when it can only be loaded once.
While I can see what you are saying about the state of the object, the most simplistic explanation of what I want to achieve is this.
How can I get a specific function/rule to run ONLY when that property has changed and not as part of the standard ValdationRules.CheckRules() routine? Checking if the property itself is dirty doesn't suffice.
It would be nice if this information was available in RuleArgs (i.e. was this called via CheckRules() or a PropertyHasChanged()). Not that I want to change the base CSLA classes, I prefer a much easier upgrade path in the future one day to CSLA4.
Thanks for your comments so far Rocky!
You can achive this in CSLA 4.2. I believe there is no plan to make any further updates to the rule engine in 3.8.x.
For CSLA 4.2 property rules you can set:
CanRunAsAffectedProperty = false; // expensive rule - do not run as affected property or as inpout property is changed CanRunInCheckRules = false; // change to true if rule can run in CheckRules CanRunOnServer = false; // Change to true if rule can run i DataAccess (logical server side of dataportal)
This will only allow the rule to run at PropertyHasChanged.
Copyright (c) Marimer LLC