1

我有一个包含一些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放在注释中,但没有运气。如何从同一个模型类中传递属性值?

4

4 回答 4

5

如果有人仍然想知道如何比较两个日期并在验证 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; }
    }
}
于 2016-07-26T15:07:42.173 回答
3

我试过只将 StartTime 放在注释中,但没有运气。如何从同一个模型类中传递属性值?

这是不可能的,因为属性是在编译时被烘焙到程序集中的元数据。这意味着您只能将CONSTANT参数传递给属性。是的,这是一个巨大的限制,因为为了执行像比较模型中的 2 个值这样明显的验证操作,您将不得不编写大量的管道代码,例如我在这里说明的内容:https://stackoverflow。 com/a/16100455/29407我的意思是,你将不得不使用反射!微软加油!你是认真的?

或者只是减少数据注释的废话并开始以正确的方式进行验证:使用FluentValidation.NET. 它允许您以非常优雅的方式表达您的验证规则,它极大地integrates with ASP.NET MVC允许您将unit test验证逻辑隔离开来。它也不依赖反射,因此速度非常快。我已经对它进行了基准测试,并在流量非常大的生产应用程序中使用它。

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

于 2013-07-18T21:01:04.633 回答
1

我喜欢哈森的回答。

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

public class EndDateValidator : 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 = Convert.ToDateTime(value); // value = EndDate
        DateTime StartDate = model.StartEffectiveDate; 

        if (StartDate > EndDate)
            return new ValidationResult("The start date must be before the end date");
        else
            return ValidationResult.Success;
    }
}

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

于 2017-09-07T20:56:22.520 回答
0
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;
    }
}

In the above example there is one issue , This solution can't be used as a common solution for validating the dates . Because the type casting of below line is not generic

var model = (CostCenterAllocationHeader)validationContext.ObjectInstance;

It means that the validation can only be applied to the specific model "costCenterAllocationHeader" . What needs to be done by passing the member name to the constructor of the validator and get the value from the ValidationContext using reflection. By this method we can use this attribute as a generic solution and can be applied in any ViewModels.

于 2019-01-03T06:55:19.747 回答