IValidatableObject Validate()用于不同的场景

时间:2012-06-23 14:42:48

标签: asp.net-mvc-3 validation

我一直在模型实体上实现 IValidatableObject ,并使用验证(ValidationContext)来执行验证,通常很复杂。

我可以使用 ValidationContext 来区分不同的验证场景吗?

e.g。以用户模型为例,我有3个验证场景:

  • 注册 - 我想测试一封电子邮件是唯一的,并且已经输入了一小部分必填字段
  • 更改详细信息 - 不同的电子邮件唯一性检查,注册后需要更多详细信息,此处不更改密码,因此无需检查
  • 更改密码 - 仅验证密码字段

这是否正确使用它,如果是这样如何我确保在帖子之后和调用Validate()之前设置正确的ValidationContext属性?或者我应该采取完全不同的方法吗?

2 个答案:

答案 0 :(得分:1)

对于我的两分钱,我会说你的模型处于有效状态(应用所有验证标准)或者不是。如果在某些情况下,您不想应用验证,那么我认为您应该使用单独的模型(实际上是ViewModel)。

在您的示例中,我会为注册创建RegisterViewModel,并为更改详细信息创建单独的EditUserViewModel。然后,每个都有自己的验证,他们将有一个single responsibility

创建一个在许多不同视图中重用的胖模型,imho,有点代码味道。我有很多理由想这个。首先,假设您有一个模型用于与用户数据的所有交互。它看起来像这样:

public class UserModel
{
    public int UserId { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public bool IsAdministrator { get; set; }
}

稍后您决定跟踪在注册网站期间使用的浏览器。你在哪里添加?它实际上与用户无关,因此不应该使用UserModel模型。如果您有一个单独的RegisterViewModel,则可以在注册过程发生变化时根据需要对其进行修改,而不必考虑它将如何影响其使用的其他位置。

如果您将上述模型与MVC的DefaultModelBinder一起使用,则会出现更严重的问题。如上所述here,即使您在表单上没有IsAdministrator字段(通过利用批量分配漏洞),用户也可以创建自己的请求并授予自己管理员权限。同样,如果使用单独的ViewModel而没有IsAdministrator属性,则会减少安全漏洞的表面积。

上面只是一个例子,但我相信你明白了。

答案 1 :(得分:1)

IValidatableObject用于对单个模型执行多次验证。在您的情况下,您拥有User模型,并且您希望进行三次验证,并且您可以通过在IValidatableObject模型中实施User来完美地完成此操作。

ValidationContext并没有带来太多好处(除了提供对上下文的访问权限),因为我们可以直接在Validate方法中访问所有属性。

通过IValidatableObject执行与单个模型相关的多个验证的示例。 (那么ValidationContext在这里的用途是什么?)

public class Party : IValidatableObject
{
    [Required(ErrorMessage = "Start date is required")]
    [FutureDateValidator(ErrorMessage = "Start date should be a future date")]
    public DateTime StartDate { get; set; }

    [Required(ErrorMessage = "Duration is required")]    
    public int DurationInHours { get; set; }

    [Required(ErrorMessage = "No. of joinees is required")]
    [Range(2, 10, ErrorMessage = "No. of joinees should be minimum 2 and not more than 10")]
    public int NoOfJoinees { get; set; }    

    public bool Drinks { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (StartDate.TimeOfDay > new TimeSpan(22 - DurationInHours, 0, 0))
        {
            yield return new ValidationResult("The party should not exceed after 10.00 PM");
        }

        if (NoOfJoinees < 5 && Drinks)
        {
            yield return new ValidationResult("Drinks are only allowed if no. of joinees is 5 or more.");
        }
    }
}