Multiple Custom Rules Per Property

Topics: Developer Forum
Apr 5, 2007 at 8:29 AM
I don't seem to be able to add multiple custom rules to a single property?

Get an exception (ArgumentException An item with the same key has already been added.) on the Add...

public virtual void Add(TItem item)
{
Guard.ArgumentNotNull(item, "item");
ValidateReadOnly();
dictionary.Add(GetKeyForItem(item), item);
}

Should I be defining it some other way?

Thx - Andrew

<property name="StartDate">
<rule typeName="CustomRuleConfigReader" ruleInterpretation="CheckPolicyStartDateNotTooFarInPast" validationMethod="CheckPolicyStartDateNotTooFarInPast" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />
<rule typeName="CustomRuleConfigReader" ruleInterpretation="CheckPolicyStartDateNotInFuture" validationMethod="CheckPolicyStartDateNotInFuture" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />
</property>
Apr 5, 2007 at 11:57 AM
Edited Apr 5, 2007 at 11:58 AM
Andrew

No VS.net access ATM so cant check this with code.

For starters make sure you have the latest code. http://www.codeplex.com/ValidationFramework/SourceControl/ListDownloadableCommits.aspx

The error you are getting is due to some code meant to stop people adding two rules that perform the same function to a given member. For example; it does not make sense to have two RequiredRules on the same property. It would just be a performance hit and would give duplicate messages to the user.

This is implimented through the use of something similar to a hashcode. Basically for all the 'things' that uniquely identify a rule hash them together. The idea is to make it fast not use up too much memory.

so in RuleCollection the code is
 protected override int GetKeyForItem(Rule item)
    {
      Guard.ArgumentNotNull(item, "item");
      return item.UniqueHash;
    } 
Since it is a hash table if two items return the same UniqueHash it will throw an exception.
The UniquHash code for CustomRule is
 public override int UniqueHash
    {
      get
      {
        return base.UniqueHash ^ validationTypeName.GetHashCode() ^ validationMethod.GetHashCode() ^ ruleInterpretation.GetHashCode();
      }
    }
Based on what you have done the two rules on the property should return different UniqueHash(s) and hence should add fine. You could get this error if you try to apply the xml config twice. I recommend putting a break point on RuleCollection.GetKeyForItem. It should only fire twice (once for each CustomRule) and should return a UniqueKey should be different each time.

Also where are you applying the rules. You should only apply rules using the ConfigurationService once in the lifetime of an appdomain. So, for instance, on startup of a windows application. Ever after they are cached, unless you programmatically clear them.

It is possible my logic for this functionality is faulty. So research it with that in mind.

Regards
Simon
Apr 5, 2007 at 12:29 PM
Hi Simon,

I will do some checks as suggested...will drop you a line later...

Thanks,
- Andrew
Apr 5, 2007 at 12:34 PM
Edited Apr 5, 2007 at 12:55 PM
Re. "Ever after they are cached, unless you programmatically clear them.", how do I do that?

MethodCache.Clear the thing to use?
Apr 5, 2007 at 1:22 PM
Edited Apr 5, 2007 at 1:23 PM
Correct.
MethodCache.Clear for methods and TypeCache.Clear for properties
But beware as those methods will clear out all method rules and property rules for all types.

To remove individual rules you would have to
for Method rules
-call MethodCache.GetMethod
-walk through the various parameter and remove individual rules
for Property rules
-call TypeCache.GetType
-walk through the various properties and remove individual rules

I will be adding some code shortly to remove rules based on xml configuration.

But all that aside, in general, you should not be removing rules progrmaitcally.
Rules should be added once (through code, attributes or xml) and then left in the cache.
They take up very little memory and exists only on a type, not instance, basis.

Do you have any particular need to remove rules form the caches?
Apr 5, 2007 at 1:53 PM
Edited Apr 5, 2007 at 1:54 PM
Hi Simon,

Have done some more testing....if I use this it gets upset..

<rule typeName="CustomRuleConfigReader" ruleInterpretation="CheckPolicyStartDateNotTooFarInPast" validationMethod="CheckPolicyStartDateNotTooFarInPast" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />
<rule typeName="CustomRuleConfigReader" ruleInterpretation="CheckPolicyStartDateNotInFuture" validationMethod="CheckPolicyStartDateNotInFuture" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />


However if I use this then all is well...not figured out why yet though!

<rule typeName="CustomRuleConfigReader" ruleInterpretation="Custom Rule" validationMethod="CheckPolicyStartDateNotTooFarInPast" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />
<rule typeName="CustomRuleConfigReader" ruleInterpretation="Custom Rule" validationMethod="CheckPolicyStartDateNotInFuture" validationTypeName="Property.Common.PropertyRuleServices.PolicyRules,Property.Common.PropertyRuleServices" />

What is ruleInerpretation supposed to be used for?

Thanks,

- Andrew




Apr 5, 2007 at 2:30 PM

SimonCropp wrote:
Correct.
MethodCache.Clear for methods and TypeCache.Clear for properties
But beware as those methods will clear out all method rules and property rules for all types.

To remove individual rules you would have to
for Method rules
-call MethodCache.GetMethod
-walk through the various parameter and remove individual rules
for Property rules
-call TypeCache.GetType
-walk through the various properties and remove individual rules

I will be adding some code shortly to remove rules based on xml configuration.

But all that aside, in general, you should not be removing rules progrmaitcally.
Rules should be added once (through code, attributes or xml) and then left in the cache.
They take up very little memory and exists only on a type, not instance, basis.

Do you have any particular need to remove rules form the caches?



I was just clearing them prior to adding in fixture setup and again in teardown. There a better approach?

TestFixtureSetUp
public void TestFixtureSetup()
{
TypeCache.Clear();
MethodCache.Clear();
ConfigurationService.AddAssembly(Assembly.Load("Property.Common.PropertyRuleServices"));
}

TestFixtureTearDown
public void TestFixtureTearDown()
{
TypeCache.Clear();
MethodCache.Clear();
}

Thanks,

- Andrew
Apr 6, 2007 at 1:28 AM
Andrew

Your code for adding custom rules should work. I will have a closer look at this on Tuesday.

Rule interpretation is purely for reporting purposes. The idea is that based on the RuleAttributes on types in an assembly you can get a text representation of what rules are where.
So RuleInterpretation is the business description of a rule that can describe a rule for developers and/or business analyst. Compared to ErrorMessage which is the descripiton of a rule for a user.
For most rules RuleInterpretation is hard coded but for CustomRule the developer needs to supply text as it is not possible to generate. It should be a readable sentence.

To output all the rules for an assembly you use ValidationRuleWriter. Unfortunately I have not updated it to process xml configuration yet.


And your use of the Clear methods for unit testing is correct. If you have a look at my unit tests you will see that I make use of them as well.
I just wanted you were not using the in the regular running of an application.
Apr 8, 2007 at 10:22 AM
This discussion has been copied to Work Item 9438. You may wish to continue further discussion there.
Apr 8, 2007 at 10:46 AM
Edited Apr 8, 2007 at 12:01 PM
Andrew

Your duplicate CustomRule problem was due to a bug with the calculation of the UniqueHash. I had not taken into account how large a Int can be generated by a large type and method name. I have changed this use the MethodHandle of the validation method.

Get the latest code for this fix.

Sorry about the bugs :)

Let me know how you go.
Apr 8, 2007 at 2:49 PM
Thanks for getting back to me over the weekend, much appreciated!

It did look like the int was exploding:)

No problem, re. bugs very grateful you're able to rectify for me!

Thanks,

- Andrew