VAB: Using both Attributes and Configuration causes problems

Jun 28, 2007 at 10:11 AM
Hello,

I'm using the VAB to validate a settings object. Attributes on properties validate their value.

The following scenario came up: After shipping the application my customer needs a higher value that we do not support and therefore forbit using VAB rules. Nevertheless he wants to try. My plan was to change the validation ranges in the configuration, send him the configuration file and he can do whatever he wants. That plan failed for different reasons:

- I can't set priorities when both sources have validation rules, they simply get validated twice and when one validation fails, everything fails. Example: Attribute allows a range of 0-50, Configuration allows 0-100. If I could set the priority to the Configuration values, a value of 70 would be valid. Currently, only 50 is valid, even though the configuration specifies a upper bound of 100.

- A bug in the Entlib denies the use of both sources at the same time: The configuration expects a System.Single (for whatever reason, I specified the values in int format), the Attributes expect a int value -> an exception occurs.

Hopefully somebody can clear this up, thanks!

Regards, Andreas


Jul 3, 2007 at 2:44 PM
Hi Andreas,

Answers to your questions inline.


testalino wrote:
Hello,

I'm using the VAB to validate a settings object. Attributes on properties validate their value.

The following scenario came up: After shipping the application my customer needs a higher value that we do not support and therefore forbit using VAB rules. Nevertheless he wants to try. My plan was to change the validation ranges in the configuration, send him the configuration file and he can do whatever he wants. That plan failed for different reasons:

- I can't set priorities when both sources have validation rules, they simply get validated twice and when one validation fails, everything fails. Example: Attribute allows a range of 0-50, Configuration allows 0-100. If I could set the priority to the Configuration values, a value of 70 would be valid. Currently, only 50 is valid, even though the configuration specifies a upper bound of 100.



Unfortunately this is by design and priorities are not supported. The validations defined in configuration and attributes are independent and both must pass in order for the validation to succeed.



- A bug in the Entlib denies the use of both sources at the same time: The configuration expects a System.Single (for whatever reason, I specified the values in int format), the Attributes expect a int value -> an exception occurs.



Can you provide further information about this issue? This quick repro didn't show this problem; is it different from your scenario? What's the type of your property?

code

using System;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

namespace VABConfigRepro
{
class Program
{
static void Main(string[] args)
{
Foo myFoo = new Foo();

myFoo.MyProperty = 2;
ValidateAndReport(myFoo);

myFoo.MyProperty = 5;
ValidateAndReport(myFoo);

myFoo.MyProperty = 8;
ValidateAndReport(myFoo);

Console.ReadLine();
}

private static void ValidateAndReport(Foo myFoo)
{
Console.WriteLine(string.Format("value {0} is valid for config: {1}", myFoo.MyProperty, Validation.ValidateFromConfiguration<Foo>(myFoo).IsValid));
Console.WriteLine(string.Format("value {0} is valid for attributes: {1}", myFoo.MyProperty, Validation.ValidateFromAttributes<Foo>(myFoo).IsValid));
Console.WriteLine(string.Format("value {0} is valid for both: {1}", myFoo.MyProperty, Validation.Validate<Foo>(myFoo).IsValid));
Console.WriteLine();
}
}

public class Foo
{
private int myVar;

RangeValidator(0, RangeBoundaryType.Inclusive, 6, RangeBoundaryType.Inclusive)
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
}
}


validation config

<validation>
<type defaultRuleset="Rule Set" assemblyName="VABConfigRepro, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="VABConfigRepro.Foo">
<ruleset name="Rule Set">
<properties>
<property name="MyProperty">
<validator lowerBound="4" lowerBoundType="Inclusive" upperBound="10"
upperBoundType="Inclusive" negated="false" messageTemplate="" messageTemplateResourceName=""
messageTemplateResourceType="" tag="" type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.RangeValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="Range Validator" />
</property>
</properties>
</ruleset>
</type>
</validation>
Jul 6, 2007 at 6:41 AM
Hey,

the scenario was a little different. I used the Windows.Forms.Integration and the ValueConvert event. In the ValueConvert event you get a property containing the type you have to convert your textbox value to. When using both the Attributes and the Configuration the type needed was either Single or int. As the ValueConvert event gets only called once you can't convert to both target types and therefore and exception gets thrown reporting that the value is not the required target type.

I don't have the code anymore, but it is basicly your sample + forms integration and ValueConvert event handler.

Regards, Andreas
Jul 6, 2007 at 2:35 PM
Hi Andreas,

I don't quite understand your scenario. The ValueConvert event will be invoked to convert the value to validate after the validator has been created, and its event contains the type of the property configured to be validated which is fixed while the application is running. Both attributes and configuration would describe validation for the same type, either int or single.

It would be great if you could post your repro code; I tried my repro with a winforms app and didn't face this problem.

Regards,
Fernando
Jul 10, 2007 at 12:15 PM
Hello,

well I put a little demo together. I don't know why, but it already failed with the same error before I even created the configuration file.

In the ValueConvert EventHandler the expected type should be Single.

here is the sample: http://testi.mine.nu/temp/VABTest.zip

I hope you can verify that, otherwise I'm probably screwed.

Regards, Andreas
Jul 10, 2007 at 1:49 PM
Edited Jul 10, 2007 at 1:50 PM
You specify an integer value in the RangeValidator attribute. Try putting a float

E.g. [RangeValidator(0F, RangeBoundaryType.Inclusive, 180F, RangeBoundaryType.Inclusive, Ruleset = "Default")]
Jul 10, 2007 at 2:11 PM
hmm, thats weird. The type of the values specified in attributes actually have to match the property type? When I change the property from float to int, it works just like that. Still, I think its a bug, the enterprise library could use something like Converter.ChangeType to match the two types, as it does not even generate a compiler warning.
Jul 10, 2007 at 3:03 PM
Or perhaps introduce generic attributes to C#
Jul 10, 2007 at 5:26 PM
Hi,

You did hit a difference in the way configuration and attributes are dealt with by the VAB: for configuration the actual type of the member is used when creating the validator, but with attributes the information in the attribute itself is used instead. The advantage of attributes is that they can be strongly typed (although not as strongly as to include the type of the member the attribute is bound to in the picture).

There is a way to overcome this issue, by losing the strongly typed nature of attributes: you can use the signature for the attribute that lets you specify the type, and the range limits as strings that get converted to the type.

Regards,
Fernando