基于其他值

时间:2017-06-30 13:51:11

标签: c# asp.net-mvc validation validationattribute

我为餐厅制作了预订表格,要求提供餐厅名称,用餐日期和人数。

我有预订课程,其中包含身份证,餐馆ID,日期和人数:

public class Booking
{
    public int Id { get; set; }
    public int IDRestaurant{ get; set; }
    [CustomPlaceValidator]
    public int Nbpeople { get; set; }
    [CustomDateValidator]
    public DateTime Date { get; set; }
}

还有一个Resto类,它有一个ID,一个名字,一个电话号码和一些表格:

public class Resto
{
    public int Id { get; set; }
    [Required(ErrorMessage = "Le nom du restaurant doit être saisi")]
    public string Nom { get; set; }
    [Display(Name = "Téléphone")]
    [RegularExpression(@"^0[0-9]{9}$", ErrorMessage = "Le numéro de téléphone est incorrect")]
    public string Telephone { get; set; }
    [Range(0, 9999)]
    public int Size { get; set; }
}

我想对每个新预订进行验证,确认餐厅未满。 为此,在验证"人数"预订领域,我需要"餐厅名称的价值"字段和"日期"的价值现场,然后在该日期检索该餐厅的所有预订,并检查人数的总和是否远低于餐厅的容量。

public class CustomPlaceValidator : ValidationAttribute
{
    private IDal dal = new Dal();
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int nb = 0;
        if (dal.GetAllBooking() != null)
        {
            foreach (var booking in dal.GetAllBooking())
                nb += booking.Nbpeople;
            if (nb ..... ) return ValidationResult.Success;
            return new ValidationResult("The restaurant is full for this date.");
        }
        return ValidationResult.Success;

    }

}

(这是一个草案,测试显然没有完成)

我如何才能获得其他礼仪的价值?

3 个答案:

答案 0 :(得分:2)

这不适用于验证属性。首先,验证属性应该是独立的,或者至少是自包含的。由于此处的逻辑取决于两个不同的属性(人数和预订日期),因此验证属性需要过多的域知识才能执行必要的验证。换句话说,它不可重复使用,如果它不可重复使用,那么使用属性就没有意义。

其次,验证属性不应该执行类似数据库查询的操作。控制器本身应该负责使用您的DAL。当您开始在整个应用程序中乱丢数据库访问时,您将开始以极短的顺序遇到各种问题。如果您使用DI容器将DAL注入其需要的位置,那么在控制器之外使用它的问题就少了,重要的是,属性确实不能很好地发挥作用依赖注入。你可以使用一些DI容器,但它从来都不容易,你可能会后来后悔。所以,再次,这不应该是验证属性处理的东西。

我认为最好的方法是在控制器上创建一个私有/受保护的方法来处理此验证。类似的东西:

public void ValidateCapacity(Booking booking)
{
    var restaurant = dal.GetRestaurant(booking.IDRestaurant);
    var existingBookings = dal.GetBookings(booking.IDRestaurant, booking.Date);
    var available = restaurant.Size - existingBookings.Sum(b => b.Nbpeople);
    if (booking.Nbpeople > available)
    {
        ModelState.AddModelError("Nbpeople", "There is not enough capacity at the restaurant for this many people on the date you've selected");
    }
}

然后,在预订的发布操作中,只需在检查ModelState.IsValid之前调用此方法。

答案 1 :(得分:0)

您要求的是跨属性验证。如果您不强烈反对在数据对象上实现接口,则应该查看以下内容:

https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.ivalidatableobject.aspx

一个小矩形类的简单示例实现,我们希望它的区域不超过37(无论该单位是什么)。

public class SmallRectangle : IValidatableObject
{
    public uint Width { get; set; }
    public uint Height { get; set; }
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var area = Width * Height;
        if (area > 37)
        {
            yield return new ValidationResult($"The rectangle is too large.");
        }
    }
}

替代

IsValidValidationAttribute函数的第二个参数为您提供了ValidationContext,其中包含属性ObjectInstance,您可以将其转换为对象类型和访问权限其他成员。但是,这会使您的验证属性特定于您的类。我通常会反对这一点。

您也可以选择使用不同的验证方法,例如使用验证库(如FluentValidations),请参阅: https://github.com/JeremySkinner/FluentValidation

不同的观点

最后但并非最不重要的是,我想指出通常应该使用验证来验证数据的完整性。请求更多座位的预订请求无效。它不能被授予,但它是一个有效的请求,不幸的是,它将以否定结果回答。在我看来,给出负面结果不是验证的责任,而是业务逻辑。

答案 2 :(得分:0)

我正在看这个问题:Group validation messages for multiple properties together into one message asp.net mvc

我的猜测是这样的:

public class Booking
{
    public int Id { get; set; }
    public int IDRestaurant{ get; set; }
    [CustomPlace("IDRestaurant", "Date", ErrorMessage = "the restaurant is full")]
    public int Nbpeople { get; set; }
    [CustomDateValidator]
    public DateTime Date { get; set; }
}

和自定义验证:

public class CustomPlaceAttribute : ValidationAttribute
{
    private readonly string[] _others
    public CustomPlaceAttribute(params string[] others)
    {
        _others= others;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
           // TODO: validate the length of _others to ensure you have all required inputs
           var property = validationContext.ObjectType.GetProperty(_others[0]);
           if (property == null)
           {
               return new ValidationResult(
                string.Format("Unknown property: {0}", _others[0])
               );
           }
           // This is to get one of the other value information. 
           var otherValue = property.GetValue(validationContext.ObjectInstance, null);

           // TODO: get the other value again for the date -- and then apply your business logic of determining the capacity          
    }
}

但是,通过

进行validationAttribute的数据库调用感觉有些麻烦
相关问题