类/模型级别验证(与财产级别相对)? (ASP.NET MVC 2.0)

时间:2010-05-06 19:31:38

标签: c# .net asp.net asp.net-mvc vb.net

基本上,标题是什么。我有几个属性组合在一起,真正做出一个逻辑答案,我想运行一个服务器端验证代码(我写),考虑到这些多个字段,并只连接到一个验证输出/错误消息,用户在网页上看到。

我查看了scott guthries扩展属性并在dataannotations声明中使用它的方法,但是,正如我所看到的,没有办法在多个属性上声明dataannotations-style属性,并且您只能放置声明(例如[电子邮件],[范围],[必需])在一个属性上:(。

我已经查看了启动新项目时出现的默认mvc 2.0项目中的PropertiesMustMatchAttribute,这个示例与使用一对引脚检查机油一样有用 - 没用!

我尝试过这种方法,但是,创建了一个类级别属性,并且不知道如何在我的aspx页面中显示错误。我已经尝试过html.ValidationMessage(“ClassNameWhereAttributeIsAdded”)和其他各种各样的东西,但它还没有用。我应该提一下,在这个级别上没有一篇关于进行验证的博客文章 - 尽管这是任何项目或业务逻辑场景中的常见需求!

任何人都可以帮助我在我的aspx页面中显示我的消息,并且如果可能的话还可以提供适当的文档或参考来解释此级别的验证吗?

6 个答案:

答案 0 :(得分:14)

现在您已经查看了数据注释并得出结论他们不适应您的情况我会建议您查看FluentValidationintegration with ASP.NET MVC以及您unit test your validation logic的方式{{3}} 3}} - 你不会失望(我真的没有任何反对数据注释,它们非常适合博客文章和教程,但是一旦你面对现实世界的应用程序,你很快就会意识到这些限制)。


更新:

根据评论部分的要求,这是一个使用FluentValidation框架和一个服务器端验证功能访问多个属性的示例(请不要这样做,因为它很丑陋,有更好的方法):

class AuthInfo
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
}

class AuthInfoValidator : AbstractValidator<AuthInfo>
{
    public override ValidationResult Validate(AuthInfo instance)
    {
        var result = base.Validate(instance);
        if (string.IsNullOrEmpty(instance.Username))
        {
            result.Errors.Add(new ValidationFailure("Username", "Username is required"));
        }
        if (string.IsNullOrEmpty(instance.Password))
        {
            result.Errors.Add(new ValidationFailure("Password", "Password is required"));
        }
        if (string.IsNullOrEmpty(instance.ConfirmPassword))
        {
            result.Errors.Add(new ValidationFailure("ConfirmPassword", "ConfirmPassword is required"));
        }
        if (instance.Password != instance.ConfirmPassword)
        {
            result.Errors.Add(new ValidationFailure("ConfirmPassword", "Passwords must match"));
        }
        return result;
    }
}

更自然的方法是:(它也不受属性重命名,因为它不包含任何魔术字符串):

class AuthInfoValidator : AbstractValidator<AuthInfo>
{
    public AuthInfoValidator()
    {
        RuleFor(x => x.Username)
            .NotEmpty()
            .WithMessage("Username is required");

        RuleFor(x => x.Password)
            .NotEmpty()
            .WithMessage("Password is required");

        RuleFor(x => x.ConfirmPassword)
            .NotEmpty()
            .WithMessage("ConfirmPassword is required");

        RuleFor(x => x.ConfirmPassword)
            .Equal(x => x.Password)
            .WithMessage("Passwords must match");
    }
}

答案 1 :(得分:3)

我不确定,但你是不是因为没有明显原因(或者我对VB.NET的观点的b / c)而不断投票给我的答案/问题的人?

无论如何,PropertiesMustMatchAttribute只是在对象上使用特定属性的值的一个很好的实现。如果您需要使用对象的多个字段运行某些逻辑,则可以使用以下内容执行此操作,类似于PropertiesMustMatchAttribute

下面是访问对象属性以运行某些逻辑的ValidationAttribute的主要部分。

    public override bool IsValid(object value)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);

        // Get the values of the properties we need. 
        // Alternatively, we don't need to hard code the property names,
        // and instead define them via the attribute constructor
        object prop1Value = properties.Find("Person", true).GetValue(value);
        object prop2Value = properties.Find("City", true).GetValue(value);
        object prop3Value = properties.Find("Country", true).GetValue(value);

        // We can cast the values we received to anything
        Person person = (Person)prop1value; 
        City city = (City)prop2value;
        Country country = (Country)prop3value;

        // Now we can manipulate the values, running any type of logic tests on them
        if(person.Name.Equals("Baddie") && city.ZIP == 123456)
        {
            return country.name.Equals("Australia");
        }
        else
        {
            return false;
        }         
    }

PropertiesMustMatchAttribute只是使用Reflection来完成一项常见任务。我试图破解代码,使其更易读/更容易理解。

答案 2 :(得分:3)

可能的Dupe:

Writing a CompareTo DataAnnotation Attribute

你的问题的答案应该在那里,至少它指向这篇博文:

http://byatool.com/mvc/custom-data-annotations-with-mvc-how-to-check-multiple-properties-at-one-time/


要显示错误消息,您必须使用:

<%: Html.ValidationMessage("") %>

所发生的情况是因为您在类级别上验证您获得带有键的ModelState,通常是属性名称,带有空字符串。

答案 3 :(得分:2)

通过ValidationAttribute中的子类创建类级属性时,如果验证失败,则ModelState =&gt;中没有相应的键。它将是一个空字符串,但在下面提供的链接中提供了解决方法,这将帮助U在您的视图中显示错误消息 通过仅使用html.ValidationMessage(“urpropertyname”)而不是U尝试html.ValidationMessage(“ClassNameWhereAttributeIsAdded”)。

Unable to set membernames from custom validation attribute in MVC2

答案 4 :(得分:2)

我知道这已经得到了回答,但是如果你想继续使用DataAnotations Attributes,MVC3似乎已经添加了另一种方法来实现这一点。

您的类可以实现提供Validate方法的IValidatableObject接口。只是另一种皮肤猫的方法。

答案 5 :(得分:1)

我使用FluentValidator完成了以下操作,如果它对任何人都有用,感谢Darin的建议:

Public Class tProductValidator
Inherits AbstractValidator(Of tProduct)


Public Sub New()
    Const RetailWholsaleError As String = "You need to enter either a Retail Price (final price to user) or a Wholesale Price (price sold to us), but not both."
    Dim CustomValidation As System.Func(Of tProduct, ValidationFailure) =
     Function(x)
         If (x.RetailPrice Is Nothing AndAlso x.WholesalePrice Is Nothing) OrElse (x.RetailPrice IsNot Nothing AndAlso x.WholesalePrice IsNot Nothing) Then
             Return New ValidationFailure("RetailPrice", RetailWholsaleError)
         End If
         Return Nothing
     End Function

    Custom(CustomValidation)
End Sub

End Class
像往常一样,我被愚弄认为MVC是一个完整的框架,真实世界的场景是可能的。他们如何发布这样的东西,甚至没有提到我不理解的局限性,我们的开发人员然后遇到的问题是一个噩梦,或者我们必须依靠第三方的东西去做本质上的MVC责任,如果第三方物品不可用 - 那么呢?

这不是我在mvc 2.0中发现的第一次严重后退,该列表不断增长。

确保团队不断给出这些“酷”的例子,说明使用虚构的非现实世界的例子是多么简单,当谈到真实的东西时,它就像“我们不知道或不关心,我们也不会告诉你它,你只需要遇到它并自己解决“输入交易

哦,除非你使用js hack并切换返回的html并将其分配给不同的div,否则仍然无法在一次往返中更新视图的多个部分...你甚至无法返回多个视图或至少在本地更新页面的多个区域(在一次往返中),这只是令人难过。

也许当MVC达到3.0版时,它可能实际上是完整的,手指交叉,因为dotnet框架实际上并非“完整”,直到clr 3.5&amp;包括linq / EF到SQL ...