Validation 是否将两个属性与自定义DataAnnotation属性进行比较?

Validation 是否将两个属性与自定义DataAnnotation属性进行比较?,validation,asp.net-mvc-4,properties,model,data-annotations,Validation,Asp.net Mvc 4,Properties,Model,Data Annotations,我有一个自定义模型,它保存一些DateTime值,还有一个自定义DataAnnotation,用于比较这些值 以下是属性及其注释: [Required] [DataType(System.ComponentModel.DataAnnotations.DataType.Date)] [Display(Name = "Start Date")] public DateTime StartTime { get; set; } [DataType(System.ComponentModel.DataA

我有一个自定义模型,它保存一些
DateTime
值,还有一个自定义
DataAnnotation
,用于比较这些值

以下是属性及其注释:

[Required]
[DataType(System.ComponentModel.DataAnnotations.DataType.Date)]
[Display(Name = "Start Date")]
public DateTime StartTime { get; set; }

[DataType(System.ComponentModel.DataAnnotations.DataType.Date)]
[Display(Name = "End Date")]
[CompareTo(this.StartTime, CompareToAttribute.CompareOperator.GreaterThanEqual)]
public DateTime? EndTime { get; set; }
CompareTo
属性就是问题所在。我得到一个错误:

Keyword 'this' is not available in the current context
我尝试只在注释中放置
StartTime
,但没有成功。如何从同一模型类传入属性值

我尝试在注释中仅放置StartTime,但运气不佳。怎么 我可以从同一个模型类传入属性值吗

这是不可能的,因为属性是在编译时烘焙到程序集中的元数据。这意味着您只能将常量参数传递给属性。是的,这是一个非常大的限制,因为为了执行一个明显的验证,比如比较模型中的两个值,你必须编写大量的管道代码,比如我在这里演示的代码:我的意思是,你必须使用反射!来吧,微软!你是认真的吗

或者干脆放弃数据注释的垃圾,开始用正确的方法进行验证:使用。它允许您以一种非常优雅的方式表达您的验证规则,它大大提高了您的效率,并允许您独立地使用您的验证逻辑。它也不依赖反射,所以速度非常快。我对其进行了基准测试,并将其用于流量非常大的生产应用中

当您开始编写比Hello World稍微复杂一点的应用程序,并且需要比Hello World应用程序更复杂一点的验证逻辑时,与命令式验证规则相比,数据注释并没有起到重要作用

我尝试在注释中仅放置StartTime,但运气不佳。怎么 我可以从同一个模型类传入属性值吗

这是不可能的,因为属性是在编译时烘焙到程序集中的元数据。这意味着您只能将常量参数传递给属性。是的,这是一个非常大的限制,因为为了执行一个明显的验证,比如比较模型中的两个值,你必须编写大量的管道代码,比如我在这里演示的代码:我的意思是,你必须使用反射!来吧,微软!你是认真的吗

或者干脆放弃数据注释的垃圾,开始用正确的方法进行验证:使用。它允许您以一种非常优雅的方式表达您的验证规则,它大大提高了您的效率,并允许您独立地使用您的验证逻辑。它也不依赖反射,所以速度非常快。我对其进行了基准测试,并将其用于流量非常大的生产应用中


当您开始编写比Hello World稍微复杂一点的应用程序,并且需要比Hello World应用程序更复杂一点的验证逻辑时,与命令式验证规则相比,数据注释并不能解决问题。

如果还有人想知道如何比较两个日期和时间在validation DataAnnotation中使用它,您可以简单地添加一个扩展方法来比较开始日期和结束日期,如下所示

假设这是您的类:

using System;
using System.ComponentModel.DataAnnotations;

namespace Entities.Models
{
    public class Periode
    {
        [Key]
        public int PeriodeID { get; set; }

        public string Name { get; set; }

        [DataType(DataType.Date)]
        [Display(Name ="Start Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime StartDate { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "End Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EndDate { get; set; }
    }
}
您只需添加以下类作为验证器:

namespace Entities.Models
{

    public class StartEndDateValidator : ValidationAttribute
    {
        protected override ValidationResult
                IsValid(object value, ValidationContext validationContext)
        {
            var model = (Models.Periode)validationContext.ObjectInstance;
            DateTime EndDate = Convert.ToDateTime(model.EndDate);
            DateTime StartDate = Convert.ToDateTime(value);

            if (StartDate > EndDate)
            {
                return new ValidationResult
                    ("The start date must be anterior to the end date");
            }
            else
            {
                return ValidationResult.Success;
            }
        }
    }
}
然后您需要在StartDate上添加该DataAnnotation,如下所示

namespace Entities.Models
{
    public class Periode
    {
        [Key]
        public int PeriodeID { get; set; }

        public string Name { get; set; }

        [DataType(DataType.Date)]
        [Display(Name ="Start Date")]
        // You need to add the following line
        [StartEndDateValidator]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime StartDate { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "End Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EndDate { get; set; }
    }
}

如果有人仍然想知道如何比较两个日期并在验证数据注释中使用它们,您可以简单地添加一个扩展方法来比较开始日期和结束日期,如下所示

假设这是您的类:

using System;
using System.ComponentModel.DataAnnotations;

namespace Entities.Models
{
    public class Periode
    {
        [Key]
        public int PeriodeID { get; set; }

        public string Name { get; set; }

        [DataType(DataType.Date)]
        [Display(Name ="Start Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime StartDate { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "End Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EndDate { get; set; }
    }
}
您只需添加以下类作为验证器:

namespace Entities.Models
{

    public class StartEndDateValidator : ValidationAttribute
    {
        protected override ValidationResult
                IsValid(object value, ValidationContext validationContext)
        {
            var model = (Models.Periode)validationContext.ObjectInstance;
            DateTime EndDate = Convert.ToDateTime(model.EndDate);
            DateTime StartDate = Convert.ToDateTime(value);

            if (StartDate > EndDate)
            {
                return new ValidationResult
                    ("The start date must be anterior to the end date");
            }
            else
            {
                return ValidationResult.Success;
            }
        }
    }
}
然后您需要在StartDate上添加该DataAnnotation,如下所示

namespace Entities.Models
{
    public class Periode
    {
        [Key]
        public int PeriodeID { get; set; }

        public string Name { get; set; }

        [DataType(DataType.Date)]
        [Display(Name ="Start Date")]
        // You need to add the following line
        [StartEndDateValidator]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime StartDate { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "End Date")]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EndDate { get; set; }
    }
}

我喜欢哈森的回答

与Hassen的例子相同,但建议: 1) 如果结束日期是可选的,则在没有结束日期时中止。 2) 将验证器置于结束日期,以防用户仅更改结束日期

数据注释:

[Required]
[Display(Name = "Start Effective Date", Description = "Start Date")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[DataType(DataType.Date)]
[StartDateValidator]
public DateTime StartEffectiveDate { get; set; }

[Display(Name = "End Effective Date", Description = "End Date")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[DataType(DataType.Date)]
[EndDateValidator]
public DateTime? EndEffectiveDate { get; set; }
代码:


会对哈森的回答发表评论,但声誉不够。

我喜欢哈森的回答

public class StartDateValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var model = (CostCenterAllocationHeader)validationContext.ObjectInstance;
        if (model.EndEffectiveDate == null)  // Abort if no End Date
            return ValidationResult.Success;

        DateTime EndDate = model.EndEffectiveDate.GetValueOrDefault();
        DateTime StartDate = Convert.ToDateTime(value);  // value = StartDate

        if (StartDate > EndDate)
            return new ValidationResult("The start date must be before the end date");
        else
            return ValidationResult.Success;
    }
}
与Hassen的例子相同,但建议: 1) 如果结束日期是可选的,则在没有结束日期时中止。 2) 将验证器置于结束日期,以防用户仅更改结束日期

数据注释:

[Required]
[Display(Name = "Start Effective Date", Description = "Start Date")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[DataType(DataType.Date)]
[StartDateValidator]
public DateTime StartEffectiveDate { get; set; }

[Display(Name = "End Effective Date", Description = "End Date")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[DataType(DataType.Date)]
[EndDateValidator]
public DateTime? EndEffectiveDate { get; set; }
代码:

会对哈森的回答发表评论,但没有足够的声誉

public class StartDateValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var model = (CostCenterAllocationHeader)validationContext.ObjectInstance;
        if (model.EndEffectiveDate == null)  // Abort if no End Date
            return ValidationResult.Success;

        DateTime EndDate = model.EndEffectiveDate.GetValueOrDefault();
        DateTime StartDate = Convert.ToDateTime(value);  // value = StartDate

        if (StartDate > EndDate)
            return new ValidationResult("The start date must be before the end date");
        else
            return ValidationResult.Success;
    }
}
在上面的示例中,有一个问题,该解决方案不能用作验证日期的通用解决方案。因为下线的类型转换不是泛型的

var model = (CostCenterAllocationHeader)validationContext.ObjectInstance;
这意味着验证只能应用于特定型号“costCenterAllocationHeader”。需要通过将成员名传递给验证器的构造函数并使用反射从ValidationContext获取值来完成什么。通过此方法,我们可以将此属性用作通用解决方案,并可应用于任何ViewModels

在上面的示例中,有一个问题,该解决方案不能用作验证日期的通用解决方案。因为下线的类型转换不是泛型的

var model = (CostCenterAllocationHeader)validationContext.ObjectInstance;

这意味着验证只能应用于特定型号“costCenterAllocationHeader”。需要通过将成员名传递给验证器的构造函数并使用反射从ValidationContext获取值来完成什么。通过此方法,我们可以将此属性用作通用解决方案,并可应用于任何ViewModels。

。。。不知道该如何应对。我应该感激吗?我应该生气吗?也许我会让观众来做评判。我想我会检查FluentValidation。你为什么会生气?无意冒犯,我猜互联网上的博客文章只是缺少了ASP.NETMVC的重要方面。这不是你的错误,你读到了某个地方的v