【问题标题】:Custom Annotations to Validate End Date Doesn't Come Before Start Date用于验证结束日期的自定义注释不会早于开始日期
【发布时间】:2013-12-12 12:52:57
【问题描述】:

对于我的预订系统,我需要检查用户在表单中输入的结束日期是否早于用户在表单中输入的开始日期。我正在使用 ASP.NET MVC 4 C Sharp。

我可以使用自定义注释来做到这一点吗?到目前为止我有这个,但是模型类中的日期下方出现红线,上面写着“属性参数必须是常量表达式......”

    private readonly DateTime _startDate;
    private readonly DateTime _endDate;

    public DateComparisonAttribute(DateTime startDate, DateTime endDate) : base ("{1} is greater than {0}. The end date must come before start date")
    {
        _startDate = startDate;
        _endDate = endDate;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            if (_endDate < _startDate)
            {
                var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                return new ValidationResult("End Date Must Come After Start Date");
            }
        }
        return ValidationResult.Success;
    }

型号:

    [DateComparison(StartDate, EndDate, ErrorMessage = "Dates")]
    [DisplayName("Start Date (MM/DD/YYYY)")]
    public DateTime StartDate { get; set; }
    [DisplayName("End Date (MM/DD/YYYY)")]
    public DateTime EndDate { get; set; }

【问题讨论】:

  • 您还需要编写 JavaScript 代码。 C# 只是 MVC 验证的一方面
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • @Liam:你应该告诉 OP 为什么双方都需要验证
  • 我很确定这也不会编译,您的 StartDate 等无法传递到属性中
  • 问题是 DateTime 返回一个运行时对象,而在属性中我们需要在编译时固定参数

标签: c# asp.net-mvc-4 data-annotations


【解决方案1】:

这是我之前根据Brad wilsons blog 的信息编写的一篇

C# 属性

public sealed class IsDateAfterAttribute: ValidationAttribute, IClientValidatable
  {
    protected abstract string GetValidationType();
    protected abstract bool CompareValues(DateTime value, DateTime propertyTestedValue, out ValidationResult validationResult);

    protected readonly string testedPropertyName;
    protected readonly bool allowEqualDates;

    protected int _maxSearchableDaysAhead;

    public IsDateAfterAttribute(string testedPropertyName, bool allowEqualDates = false)
    {
      this.testedPropertyName = testedPropertyName;
      this.allowEqualDates = allowEqualDates;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
      var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName);
      if (propertyTestedInfo == null)
      {
        return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName));
      }

      var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

      if (value == null || !(value is DateTime))
      {
        return ValidationResult.Success;
      }

      if (propertyTestedValue == null || !(propertyTestedValue is DateTime))
      {
        return ValidationResult.Success;
      }

      ValidationResult returnVal;
      if (CompareValues((DateTime)value, (DateTime)propertyTestedValue, out returnVal))
      {
        return returnVal;
      }
      else
      {
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
      }



    }

    protected override bool CompareValues(DateTime value, DateTime propertyTestedValue, out ValidationResult validationResult)
{
  validationResult = null;
  // Compare values
  if (value <= propertyTestedValue)
  {
    if (this.allowEqualDates)
    {
      validationResult = ValidationResult.Success;
      return true;
    }
    if (value < propertyTestedValue)
    {
      validationResult = ValidationResult.Success;
      return true;
    }

  }


  return false;
}

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {

      this._maxSearchableDaysAhead = Setting.GetSettingValue(SettingNames.MaxSearchableDaysAhead, 548);

      var rule = new ModelClientValidationRule
      {
        ErrorMessage = string.Format(this.ErrorMessageString, _maxSearchableDaysAhead),
        ValidationType = "isdateafter"
      };
      rule.ValidationParameters["propertytested"] = this.testedPropertyName;
      rule.ValidationParameters["allowequaldates"] = this.allowEqualDates;
      yield return rule;
    }
  }

JS

$.validator.unobtrusive.adapters.add(
    'isdateafter', ['propertytested', 'allowequaldates'], function (options) {
        options.rules['isdateafter'] = options.params;
        options.messages['isdateafter'] = options.message;
    });
    $.validator.addMethod("isdateafter", function (value, element, params) {
        var parts = element.name.split(".");
        var prefix = "";
        if (parts.length > 1)
            prefix = parts[0] + ".";
        var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val();
        if (!value || !startdatevalue)
            return true;
        if (params.allowequaldates && params.allowequaldates.toLowerCase() == "true") 
                {
                    return Date.parse(startdatevalue) <= Date.parse(value); 
                }
                else
                {
                    return Date.parse(startdatevalue) < Date.parse(value);
                }
    });

添加到模型

[DisplayName("Departure Dates")]
 public DateTime? DepartureFrom { get; set; }

 [DisplayName("Departure Dates")]
 [IsDateAfter("DepartureFrom", true, ErrorMessage = "* Departure To Date must be after Departure From Date")]
 public DateTime? DepartureTo { get; set; }

【讨论】:

  • 此解决方案使用昂贵的反射。我不想添加到许多模型中。
  • 由于给出了答案,因此引入了“nameof”运算符 - 将其添加到属性声明 [IsDateAfter(nameof(DepartureFrom), 使其在重构属性名称时更加健壮。还有是使用可以与客户端验证连接的属性与使用 IValidateableObject 进行服务器端验证而不进行反射之间的权衡:事实证明,混合模式永远不会同时处理两个属性和 IValidateableObject.Validate。仅当没有属性时(或:没有验证失败)接口被触发。
【解决方案2】:

属性必须是常量,因为它们是在编译时添加到程序集的。所以,不,你不能通过自定义注释得到你想要的。

【讨论】:

  • 你错了,开箱即用不,但你可以创建自己的自定义。
  • 你错了,属性中使用的值必须是常量。无论属性是库存还是自定义。
  • 你可以使用反射和Jquery。看我的回答
  • 是的,具有巨大的性能影响。这种类型的验证最好在服务器端完成。
  • 反射不会增加巨大的性能影响。反射添加是一个开销,是的,它不是巨大。它是如此之小,以至于我无视你注意到平均系统的任何差异。 See here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多