Validation Block: Bug in RangeValidator

Topics: Validation Application Block
Apr 22, 2007 at 4:28 PM
A subtle bug that is easy to work around in the RangeValidator, but IMHO should be fixed.

Via configuration, I set the UpperBoundType to Ignore when validating a range of integers, but if you don't put an integer in the UpperBound you will get an exception:

[IndexOutOfRangeException: Index was outside the bounds of the array.]
   System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) +371
 
[Exception:  is not a valid value for Int32.]
   System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) +390
   System.ComponentModel.TypeConverter.ConvertFromString(ITypeDescriptorContext context, CultureInfo culture, String text) +15
   Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.RangeValidatorData.DoCreateValidator(Type targetType) +181
   Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidatorData.DoCreateValidator(Type targetType, Type ownerType, MemberValueAccessBuilder memberValueAccessBuilder) +32

Clearly if I can truly ignore the lower or upper bound range I shouldn't have to enter anything. Bug might occur when ignoring the lower bound as well but didn't check.

I was using it with the PIAB when the bug occurred:

[ValidationCallHandler("Default")]
public void Save( ... )
{
}

Regards,

Dave

_________________________

David Hayden
Microsoft MVP C#
Aug 21, 2007 at 1:02 AM
We're running into similar issues (same error message) when attempting to use validation on a control that should map to an Int property on a business object. It is not just
the RangeValidator for us, we get the same error ( is not a valid value for Int32.) when trying to use a custom validator. I'll post the Exception stack trace here.

If we remove validation attributes from the Int property of the business object then our exceptions go away. We've tried MaskedTextbox, Textbox, and NumericUpDownControls.
No matter what we do, the moment we put Validation attributes on our Int property in the business object, we run into problems if the data on the control is not a valid Int.

For instance: take a MaskedTextBox and enter two spaces instead of numbers. Then we Tab off that control to another, and our program crashes, and we get the following exception:

Type : System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Message :  is not a valid value for Int32.
Source : System
Help link : 
Data : System.Collections.ListDictionaryInternal
TargetSite : System.Object ConvertFrom(System.ComponentModel.ITypeDescriptorContext, System.Globalization.CultureInfo, System.Object)
Stack Trace :    at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Integration.ValidationIntegrationHelper.PerformValueConversion(Object& value, String& valueRetrievalFailureMessage)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Integration.ValidationIntegrationHelper.GetValue(Object& value, String& valueRetrievalFailureMessage)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.PropertyMappedControlValueAccess.GetValue(Object source, Object& value, String& valueAccessFailureMessage)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Validators.ValueAccessValidator.DoValidate(Object objectToValidate, Object currentTarget, String key, ValidationResults validationResults)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Validator.Validate(Object target)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.ValidationProvider.PerformValidation(ValidatedControlItem validatedControlItem)
   at Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.ValidatedControlItem.OnValidating(Object source, CancelEventArgs e)
   at System.ComponentModel.CancelEventHandler.Invoke(Object sender, CancelEventArgs e)
   at System.Windows.Forms.Control.OnValidating(CancelEventArgs e)
   at System.Windows.Forms.Control.PerformControlValidation(Boolean bulkValidation)
   at System.Windows.Forms.ContainerControl.ValidateThroughAncestor(Control ancestorControl, Boolean preventFocusChangeOnError)
   at System.Windows.Forms.ContainerControl.EnterValidation(Control enterControl)
   at System.Windows.Forms.ContainerControl.UpdateFocusedControl()
   at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value)
   at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator)
   at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value)
   at System.Windows.Forms.ContainerControl.SetActiveControl(Control ctl)
   at System.Windows.Forms.ContainerControl.set_ActiveControl(Control value)
   at System.Windows.Forms.Control.Select(Boolean directed, Boolean forward)
   at System.Windows.Forms.Control.SelectNextControl(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap)
   at System.Windows.Forms.ContainerControl.ProcessTabKey(Boolean forward)
   at System.Windows.Forms.ContainerControl.ProcessDialogKey(Keys keyData)
   at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
   at System.Windows.Forms.ContainerControl.ProcessDialogKey(Keys keyData)
   at System.Windows.Forms.TextBoxBase.ProcessDialogKey(Keys keyData)
   at System.Windows.Forms.Control.PreProcessMessage(Message& msg)
   at System.Windows.Forms.Control.PreProcessControlMessageInternal(Control target, Message& msg)
   at System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(MSG& msg)
Aug 21, 2007 at 3:34 PM
Hi,

The conversion exception should have been caught, but it seems like this particular error is not signaled with the expected exception.

You can work around this by providing your own custom conversion to handle this case gracefully by providing a handler for the ValueConvert event on the ValidationProvider component.

Hope this helps,
Fernando
Aug 21, 2007 at 3:35 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Aug 21, 2007 at 10:56 PM

fsimonazzi wrote:
Hi,

The conversion exception should have been caught, but it seems like this particular error is not signaled with the expected exception.

You can work around this by providing your own custom conversion to handle this case gracefully by providing a handler for the ValueConvert event on the ValidationProvider component.

Hope this helps,
Fernando


Yeah, we thought of that before I posted this and indeed, we tried it and it worked.

But it seem like a real kludge to us.

It seems to me that since there is no "Int32" control in Windows Forms (unlike the DataTimePicker, which uses a DateTime
for a value, or the NumericUpDown, which uses a Decimal for a value) that it made sense to us that when you attempt to
validate a TextBox, for instance, if you're trying to validate its value in a range of valid integers, then somewhere in the validation
itself this conversion should be attempted and if it fails, that's a failure to validate, not something that should cause an exception.

For instance, if I were to validate a TextBox manually (by wiring up to its Validating event) I would do something like this:

 
int result; 
if(!Int.TryParse(_myTextBox.Text, out result))
{
   e.Cancel = true;
   _errorProvider.SetError(_myTextBox, "Entry must be a valid number");
}

In such a case the failure to parse it as an integer shouldn't cause an exception; it should just cause a false validation result.

Aug 22, 2007 at 11:19 PM
Hi,

I agree, it should result in a validation failure just as other conversion errors do. Logged it as a work item.

Regards
Fernando
Aug 26, 2008 at 8:50 AM
Edited Aug 26, 2008 at 8:53 AM
I get this error as well. Please forgive my ignorance, but why can I not use a RangeValidator with a decimal?
Is there a special reason why decimals shouldn't be range checked? What am I missing?

I have validation in attributes (see property below).
Without thinking all that much, I can see no reason why this shouldn't work...
let alone give me an Exception: ArgumentException  - object must be of type Int32

[RangeValidator(500, RangeBoundaryType.Inclusive, 0, RangeBoundaryType.Ignore)]
public decimal Amount { get; set; }
Aug 26, 2008 at 3:15 PM
Hi,

Try specifying the validator like this: 


   
[RangeValidator(typeof(decimal), "500", RangeBoundaryType.Inclusive, "0", RangeBoundaryType.Ignore)]

Fernando