roryok roryok - 4 days ago 6
C# Question

Integer validation against non-required attributes in MVC

I've trying to validate a property on a model I have. This property is NOT required, and so if its invalid MVC seems to be ignoring it. I've even created a custom ValidationAttribute, but nothing works.

public class NumberWang : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return true;

int g;
if (int.TryParse(value.ToString(), out g))
{
if (g >= 0)
return true;
}
return false;
}
}

public class MyModel
{
[Range(0, 999999, ErrorMessage = "category_id must be a valid number")]
[NumberWang(ErrorMessage = "That's NumberWang!")]
public int? category_id { get; set; }

/* there are other properties of course, but I've omitted them for simplicity */

public void Validate()
{
Validator.TryValidateProperty(this.category_id,
new ValidationContext(this, null, null) { MemberName = "category_id" },
this.validation_results);
}
}


If I pass the value 'abc' as a category_id to this model, it validates just fine. What am I doing wrong?

Answer

I found an ugly workaround.

It seems that if category_id is a nullable int? and my value is not a valid number, a null value is passed, and the model doesn't see the invalid 'abc' value.

[Range(0, 999999, ErrorMessage = "category_id must be a valid number")]
public int? category_id { get; set; }

// when we pass a good number
MyAction?category_id=123
validation: successful

// when we pass a bad number
// validation ignores it. not what we want. 
MyAction?category_id=abc
validation: successful

If I change category_id to a non-nullable int, it fails validation even when no value is passed.

[Range(0, 999999, ErrorMessage = "category_id must be a valid number")]
public int? category_id { get; set; }

// when we pass a good number
MyAction?category_id=123
validation: successful

// when we pass an bad number
MyAction?category_id=abc
validation: "category_id must be a valid number"

// BUT, when we don't pass any number at all ... 
MyAction 
validation: "category_id must be a valid number"

The Ugly Workaround

If I change category_id to a string, and then only convert it to an int when I need it, I can validate it properly, using only [Range]

[Range(0, 999999, ErrorMessage = "category_id must be a valid number")]
public string category_id { get; set; }

// when we pass a good number
MyAction?category_id=123
validation: successful

// when we pass a bad number
MyAction?category_id=abc
validation: "category_id must be a valid number"

// no number, no validation. hooray!
MyAction 
validation: successful

It's ugly, but it works.

(Note: the custom attribute was not needed, so I removed it and just used [Range])

Comments