When I code gen a base class I get a rule for password like this:
ValidationRules.AddRule(
AddressOf StringMaxLength, New MaxLengthRuleArgs("Password", 256))In my derived class I override AddBusinessRules and add additional rules. The question is what happens if I use the same rule as defined in the base class and change the maxLength?
Like this:
ValidationRules.AddRule(
AddressOf StringMaxLength, New MaxLengthRuleArgs("Password", 128))1. Will both rules exist and be called? (So the rule is broken if password is over 128 characters long).
2. Will only the Base rule exist? (256)
3. Will only the Derived rule exist? (128)
Joe
Let us know when you test it and find out!
Curious minds want to know! :)
I think both will be called, but the order of execution will be indeterminate unless you use priorities. And the order of execution matters, because both rules will resolve to the same rule name - which is the key used in BrokenRulesCollection to maintain the list.
So if the 128 runs first, the 256 rule would remove the broken entry. But if 256 runs first, the 128 rule could break and stay in the broken rules list.
If you use priorities, you could force the 128 rule to run at priority 1, so it would run after the 256 rule. If you do that, you'll probably want to change the stop processing threshold to 2 (it defaults to 1) to ensure that the 128 rule always runs.
Rocky,
Makes sense. I plan to use Priority 1 rules for all rules that hit the DB.
I can set this rule the same way. My understanding of the processing is that all level 0 rules get run first and only if all of them pass do the level 1 rules get run. So I should not need to modify the stop processing threshold, correct?
Here is what the ebook said about it:
"In this case, I have explicitly set the ProcessThroughPriority to 0, which is the default.
This means that all priority 0 rule methods will be invoked, regardless of success or failure.
But rules at priority 1 or higher will only be invoked if no prior rule has returned Falsewith
a severity if Error."
david.wendelken:Is there a way to modify a rule after it has been assigned? Because if there is, you could just change the rule in the base class to the correct setting.
You can't modify the rules in CommonRules, nor can you ever modify a RuleArgs once it has been set up (except from within the rule method itself).
However, you could certainly create a rule method that relied on some external MaxLengthForPropertyX value, rather than a value provided through the RuleArgs - and then the value could change as often as you'd like.
RockfordLhotka:david.wendelken:Is there a way to modify a rule after it has been assigned? Because if there is, you could just change the rule in the base class to the correct setting.You can't modify the rules in CommonRules, nor can you ever modify a RuleArgs once it has been set up (except from within the rule method itself).
However, you could certainly create a rule method that relied on some external MaxLengthForPropertyX value, rather than a value provided through the RuleArgs - and then the value could change as often as you'd like.
That seems like a much cleaner and much more reliable way to do it.
RockfordLhotka:However, you could certainly create a rule method that relied on some external MaxLengthForPropertyX value, rather than a value provided through the RuleArgs - and then the value could change as often as you'd like.
I go back to this original suggestion, as it seems (by far) to be the simplest solution.
Rocky,
I used your suggestion before for getting a list of Status values. I code gen one but if it needs to be changed I just override the function which is called by the rule.
So I did the same thing here:
In Gen:
Protected Overrides Sub AddBusinessRules()
'Id
ValidationRules.AddRule(AddressOf StringMaxLength, New MaxLengthRuleArgs("Id", GetIdMaxLength))
End Sub
Public Overridable Function GetIdMaxLength() As Integer
Return 30
End Function
In final type:
Public Overrides Function GetIdMaxLength() As Integer
Return 40
End Function
Joe
RockfordLhotka:I think both will be called, but the order of execution will be indeterminate unless you use priorities. And the order of execution matters, because both rules will resolve to the same rule name - which is the key used in BrokenRulesCollection to maintain the list.
So if the 128 runs first, the 256 rule would remove the broken entry. But if 256 runs first, the 128 rule could break and stay in the broken rules list.
If you use priorities, you could force the 128 rule to run at priority 1, so it would run after the 256 rule. If you do that, you'll probably want to change the stop processing threshold to 2 (it defaults to 1) to ensure that the 128 rule always runs.
Rocky,
I just ran into the reverse case and the setting of priority will not work.
e.g. Code gen rule is for 128 but the final type rule is for 256. So if the 128 rule breaks then 256 rule will never run if it is priority 1.
You stated: "the order of execution will be indeterminate ".
I agree with that statement when discussing normal Delegate functions. But in this case aren't you storing references to the delegates in a list which you loop over to execute them? So isn't the execution order in fact determined by when the rule is added to the list? If I know my code gened rule is added to the list first and then I write a looser rule in my final type (at the same priority level) then it will be added to the list after the code gened rule and should essentially "override" it. Do you agree with this or did I miss something?
Joe
The order of execution within a priority is
indeterminate. The items get sorted, and I don’t know how the sort
algorithm works (it is Microsoft’s), so you can’t guarantee order
of execution.
However, the answer to your issue is to raise the stop
processing threshold from 1 to 2 (or something >1 anyway). This is a
static/Shared method on ValidationRules and can be set in AddBusinessRules().
Rocky
From: JoeFallon1
[mailto:cslanet@lhotka.net]
Sent: Wednesday, June 13, 2007 8:47 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Validation Rule Question
RockfordLhotka:
I think both will be called, but the order of execution will be indeterminate unless you use priorities. And the order of execution matters, because both rules will resolve to the same rule name - which is the key used in BrokenRulesCollection to maintain the list.
So if the 128 runs first, the 256 rule would remove the broken entry. But if 256 runs first, the 128 rule could break and stay in the broken rules list.
If you use priorities, you could force the 128 rule to run at priority 1, so it would run after the 256 rule. If you do that, you'll probably want to change the stop processing threshold to 2 (it defaults to 1) to ensure that the 128 rule always runs.
Rocky,
I just ran into the reverse case and the setting of priority will not work.
e.g. Code gen rule is for 128 but the final type rule is for 256. So if the 128
rule breaks then 256 rule will never run if it is priority 1.
You stated: "the order of execution will be indeterminate ".
I agree with that statement when discussing normal Delegate functions. But
in this case aren't you storing references to the delegates in a list which you
loop over to execute them? So isn't the execution order in fact determined
by when the rule is added to the list? If I know my code gened rule is added to
the list first and then I write a looser rule in my final type (at the same
priority level) then it will be added to the list after the code gened rule and
should essentially "override" it. Do you agree with this or did I
miss something?
Joe
Rocky,
I re-read the 2.1 doc on Rule Priorities and see what you mean now.
ValidationRules.ProcessThroughPriority = 1 will force all rules at level 0 and level 1 to be run even if there are broken rules in level 0. They normally stop at level 0 becasue that is the default value of this setting.
I also see where the sorting can make the rule execution order nondeterministic within a priority.
Thanks for clearing this up.
Joe
Rocky,
There is a problem with the strategy you mentioned above.
If my Gen code has this rule:
ValidationRules.AddRule(
AddressOf StringMaxLength, New MaxLengthRuleArgs("Id", 30))and my finale type has this code:
Protected Overrides Sub AddBusinessRules()The idea was that the rule would break when Id is > 30 but then when the priority 1 rule ran it would "unbreak the rule" and remove it from the Broken Rules collection.
The problem is in the line of code below form the Remove method:
If Me(index).RuleName = rule.RuleName Then
Friend Overloads Sub Remove(ByVal rule As IRuleMethod)
IsReadOnly = False
For index As Integer = 0 To Count - 1
If Me(index).RuleName = rule.RuleName Then
DecrementCount(Me(index))
RemoveAt(index)
Exit For
End If
Next
IsReadOnly = True
End Sub
The problem is this:
Me(index).RuleName = "rule://StringMaxLength/Id?maxLength=30"
rule.RuleName = "rule://StringMaxLength/Id?maxLength=40"
So the rule does not get unbroken because the names are different by the maxLength parameter.
I think I would prefer to not change the rule name itself so that I lose the extra information.
e.g. Do not change it to: "rule://StringMaxLength/Id"
Perhaps the Remove method should search the RuleName string for a ? and if it finds one then grab everything up to the ? and then compare it to the passed in value. This way the rule names are "the same" and we can ubreak the original rule.
Joe
Copyright (c) Marimer LLC