2010-11-30 47 views
1

这里有一个简单的验证属性我写了强制执行数只字符串(我用它来验证电话号码,邮政编码和一样):ValidationAttribute的值总是空

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; 
    } 

} 

的问题是,使用时验证不是字符串,比方说,一个小数,短,int或别的什么,object value总是null。为什么要验证仅限数字的小数?因为如果我不这样做,我得到默认的验证消息“值‘X’无效‘propertyName的’。我意识到默认验证消息的特定问题的解决方案。

我只是想知道为什么它总是空...

顺便说一句,我使用VS2008,ASP.NET MVC 2(最终),.NET 3.5 SP1。

回答

1

好,感谢@mcl的提示调试一路下跌(查看>控制器>模型)来验证属性!

这里发生了什么:在绑定到任何一个文本框,这不是模型中的一个串中插入无效的输入时,'DefaultModelBinder'将它的值'null'达到甚至控制器之前! (任何人有更多的信息?我会很高兴!)

1

你肯定是value是零,而不仅仅是stringValue

所以sayeth的MSDN你as运营商:

as运算符相似,但它产生在转换失败而不是引发异常空铸造。

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

在该网页上的例子就说明NUMERICS不as为字符串你想要的方式。

你可以尝试.ToString()代替。

+0

创建一个简单的测试属性,逐行扫描:`value`为空,除了字符串。 – BrunoSalvino 2010-12-01 00:55:40

+1

非常神秘,因为像decimal或short或int这样的数字属性首先不能为null。我的猜测是,你需要在调试器中返回堆栈以查看“value”来自哪里,以了解为什么传入null。无论如何,如果确实得到小数或小数或一个int作为`value`传入,`as`将失败,`stringValue`将为空。 – mlibby 2010-12-01 01:03:06

+1

是的,明白了。更多的测试,在这里我去...谢谢! – BrunoSalvino 2010-12-01 01:04:07

1

如果你的方案是你试图将你的验证器粘在int,decimal等的属性上,值进来不能转换为int,decimal等,那么这是有意的。

考虑你要求MVC框架做什么。该物业是int类型,所以MVC框架正在与int类型的值。 (从技术上讲,它的工作方式与Nullable <int>类似。)如果传入值不能转换为int,则无法将其表示为可空的<int>而不是null,因为该类型不能包含任意字符串。所以这就是为什么您的验证属性最终会以null作为值。

编辑:

如果你想控制这个错误信息,最简单的方法是将属性更改为一个字符串,然后让你自定义的验证电话的Int32。TryParse或任何你需要它来做的事情,以验证用户输入的内容是数字。然后,您可以拥有一个单独的只读属性,该属性基本上是该属性值的数字形式。

更复杂但更普遍的是,您可以用您自己创建的内置DefaultModelBinder替换。从BindModel方法中,在ModelState中查找FormatException类型的异常,然后用您选择的错误消息替换它们。查看方法DefaultModelBinder.BindProperty的结尾,以获得如何完成的示例。

0

当我将自定义验证程序附加到由另一个类型的私有变量支持的属性时,我遇到了同样的问题。例如:

private DateTime _dt; 

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

如果您通过DateTimeString =“foobar”;当LocalizedValidDateAttribute.IsValid()触发时,它将尝试获取DateTimeString的值,该值将为空,因为“foobar”不是字符串。

希望这会帮助其他人在那里保存2小时,我花了我的时间。