开发者

ValidationAttribute's value always null

Here's a simple validation attribute I wrote to enforce number-only strings (I use it to validate phone numbers, postal codes and alike):

public class NumericAttribute : ValidationAttribute {

    public NumericAttribute() {
        ErrorMessage = SharedModelResources.ValidationStrings.Numeric; // Message coming from a .resx file
    }

    public override bool IsValid(object value) {

        string stringValue开发者_高级运维 = value as string;

        if (stringValue.IsNotNull())
            foreach (var c in stringValue)
                if (!char.IsDigit(c))
                    return false;

        return true;
    }

}

The problem is that when used to validate other than strings, let's say a decimal, short, int or anything else, object value is ALWAYS null. Why validate numeric only decimals? Because if I don't, I get the default validation message 'The value 'x' is not valid for 'propertyName'. I'm aware of the solutions for the specific problem of the default validation message.

I just want to understand WHY it's always null...

BTW, I'm using VS2008, ASP.NET MVC 2 (final), .NET 3.5 SP1.


Are you positive it is value that is null and not just stringValue?

So sayeth the MSDN about your as operator:

The as operator is like a cast except that it yields null on conversion failure instead of raising an exception.

http://msdn.microsoft.com/en-us/library/cscsdfbt%28VS.71%29.aspx

In the examples on that page it shows that numerics do not as to strings the way you want.

You might try .ToString() instead.


Ok, thanks @mcl for suggesting debugging all the way down (View > Controller > Model) to the validation attribute!

Here's what happened: when inserting invalid input in a textbox binded to anything that's not a string in the model, the ´DefaultModelBinder´ sets it's value to ´null´ before it reaches even the controller! (Anyone have more info on that? I would be glad!)


If your scenario is that you're trying to stick your validator on a property of type int, decimal, etc., and the value coming in isn't convertible to int, decimal, etc., then this is intentional.

Consider what you're asking the MVC framework to do. The property is of type int, so the MVC framework is working with values of type int. (Technically, it's working with something more akin to Nullable<int>.) If the incoming value isn't convertible to int, there's no way to represent that in a Nullable<int> other than null since that type can't contain arbitrary strings. So that's why your validation attribute ends up getting null as a value.

Edit:

If you want to control this error message, the easiest option is to change the property to a string, then have your custom validator call Int32.TryParse or whatever you need it to do in order to verify that what the user typed is numeric. Then you can have a separate read-only property that's basically the numeric form of that property's value.

More complex but more generalized, you could replace the built-in DefaultModelBinder with one of your own creation. From within the BindModel method, look for exceptions of type FormatException in ModelState, then replace them with the error message of your choosing. See the end of the method DefaultModelBinder.BindProperty for an example of how this is done.


I had the same problem when I was attaching the custom validator to a property that was backed by a private variable of another type. For example:

    private DateTime _dt;

    [LocalizedValidDateAttribute("Resources.DateTimeOffsetModel.App_GlobalResources", "TimePart_Invalid")]   
    public string DateTimeString
    {
        get { return _dt.ToString(); }
        set { DateTime.TryParse(value, out _dt); }
    }    

If you pass DateTimeString = "foobar"; When LocalizedValidDateAttribute.IsValid() fires it's going to try to get the value of DateTimeString, which will be null because "foobar" is not a string.

Hopefully this will help someone else out there save the 2 hours it took me to figure it out.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜