c# - ASP.NET MVC : validating age > 18 having 3 combo box

标签 c# asp.net-mvc

我有 3 个组合框显示 MVC 中的出生年月日。我想计算年龄并禁止动态小于 18 岁的人注册。虽然是 JS。

类似于此图像中显示的内容: enter image description here

这是通过使用 DataAnnotations 和 EditorFor 完成的。实际的源代码类似于以下内容。我应该如何修改以同时验证 3 个控件?

[Required(ErrorMessageResourceType = typeof (Resources), 
          ErrorMessageResourceName = "RequiredField")]
[Range(1, 31)]
[LocalizedDisplayName(typeof (RA.Resources), "RegistrationDayOfBirth")]
public int BirthDay { get; set; }

[Required(ErrorMessageResourceType = typeof (Resources), 
          ErrorMessageResourceName = "RequiredField")]
[Range(1, 12)]
[LocalizedDisplayName(typeof (RA.Resources), "RegistrationMonthOfBirth")]
public int BirthMonth { get; set; }

[Required(ErrorMessageResourceType = typeof (Resources), 
          ErrorMessageResourceName = "RequiredField")]
[Range(1800, int.MaxValue, ErrorMessageResourceType = typeof (Resources),
       ErrorMessageResourceName = "MoreThanFieldRequired")]
[LocalizedDisplayName(typeof (RA.Resources), "RegistrationYearOfBirth")]
public int BirthYear { get; set; }

[LocalizedDisplayName(typeof (RA.Resources), "RegistrationDateOfBirth")]
public DateTime DateOfBirth { get; set; }

最佳答案

如果您想坚持使用 3 字段方法并进行动态验证(即,如果我明天 18 岁生日,今天拒绝我访问,但明天让我进入),您将需要发挥创意。

然后您需要创建一个自定义验证器和一些自定义属性。

如何进行此操作取决于您要完成的工作量,以及您要在何处应用验证逻辑。

仅服务器端验证

最简单的选择是在类本身上定义它 - 但是这将限制您只能进行服务器端验证。

创建一个在类级别应用的自定义属性,期望类上有三个字段(我添加了一个接口(interface)来简化这个并且不需要反射)并根据需要验证它:

// Interface to define individual fields:
public interface IHasIndividualDateOfBirth
{
  int BirthDay { get; set; }
  int BirthMonth { get; set; }
  int BirthYear { get; set; }
}

// Note new class level attribute, and interface declaration:
[MinAge(AgeInYears = 18)]
public class Birthday: IHasIndividualDateOfBirth
{
  [Required]
  [Range(1, 31)]
  public int BirthDay { get; set; }
  [Required]
  [Range(1, 12)]
  public int BirthMonth { get; set; }
  [Required]
  [Range(1800, 2200)]
  public int BirthYear { get; set; }

  public DateTime BirthDate { get; set; }
}

// Declare a new ValidationAttribute that can be used at the class level:
[AttributeUsage(AttributeTargets.Class)]
public class MinAgeAttribute : ValidationAttribute
{
  public int AgeInYears { get; set; }

  // Implement IsValid method:
  protected override ValidationResult IsValid(object value, 
                                              ValidationContext validationContext)
  {
    // Retrieve the object that was passed in as our DateOfBirth type
    var objectWithDob = validationContext.ObjectInstance 
                          as IHasIndividualDateOfBirth;

    if (null != objectWithDob)
    {
      // TODO: Handle invalid dates from the front-end (30 Feb for example)
      DateTime dateOfBirth = new DateTime(objectWithDob.BirthYear, 
                                          objectWithDob.BirthMonth, 
                                          objectWithDob.BirthDay);

      // Check that the age is more than the minimum requested
      if (DateTime.Now >= dateOfBirth.AddYears(AgeInYears))
      {
        return ValidationResult.Success;
      }

      return new ValidationResult("You are not yet 18 years old");
    }

    return new ValidationResult("Class doesn't implement IHasIndividualBirthday");
  }
}

虽然实现 IValidatableObject 可能看起来更简单,但它不像使用属性那样灵活,而且(像上面基于类的验证)不提供执行客户端的方法验证。

其他选项是创建一个依赖于许多其他字段的验证器(在这种情况下,您可能需要使用反射来查找其他字段,并确定哪些字段去哪里)并且您需要确保您只触发一次验证器(而不是在每个字段上),或者为 DateTime 属性编写一个自定义验证器和编辑器,而不是呈现一个您可以将日历控件放到其中的单个字段,创建三个单独的字段之后。

客户端和服务器端验证

要使客户端验证正常工作,您需要在属性级别执行此操作,这将需要您做一些额外的工作 - 例如,您可以使用模型上的 DateTime 字段作为隐藏字段当用户填写各个字段时通过 JS 填充,然后对其进行验证。

然后您的属性将需要实现 IClientValidatable,这将使您能够连接到客户端验证选项,并在元素上呈现一些元数据以公开年龄要求:

[AttributeUsage(AttributeTargets.Property)]
public class MinAgeAttribute : ValidationAttribute, IClientValidatable
{
  public int AgeInYears { get; set; }

  protected override ValidationResult IsValid(object value,
                                              ValidationContext validationContext)
  {
    // [Similar to before]
  }

  public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
                                                        ModelMetadata metadata,
                                                        ControllerContext context)
  {
    return new[]
    {
      new ModelClientValidationMinAgeRule(ErrorMessage, AgeInYears)
    };
  }
}

public class ModelClientValidationMinAgeRule : ModelClientValidationRule
{
  public ModelClientValidationMinAgeRule(string errorMessage, int ageInYears)
  {
      ErrorMessage = errorMessage;
      // Validation Type and Parameters must be lowercase
      ValidationType = "minage";
      ValidationParameters.Add("ageinyears", ageInYears);
  }
}

然后对于客户端,您需要将一些自定义验证器注册到 jQuery.Validate 或类似工具中(我推荐您自己的 JS 文件包含在 jqueryval 包中):

$(function ($) {
  $.validator.addMethod("minage", function(value, element, params) {
    if ($(element).val() != '') {

      var ageInYears = params;

      // take date from BirthDate element and compare with ageInYears.
      return false;
    }
  });

  $.validator.unobtrusive.adapters.addSingleVal("minage", "ageinyears");
}(jQuery));

关于c# - ASP.NET MVC : validating age > 18 having 3 combo box,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26342936/

相关文章:

c# - 广告控件不显示任何内容并在 Windows Phone 应用程序上消失

C# .NET 图表库/代码?

c# - 在 EndAccept() 之前或之后开始接受新连接

css - 在 ASP.NET MVC 中的标题下方设置导航栏

javascript - 获取 DateTime 的日期部分(ASP.NET MVC)

asp.net-mvc - 如何在 LINQ 中查询列表

asp.net-mvc - ASP.NET MVC GoogleBot 问题

c# - SpeechRecognitionEngine.AudioLevel 不变

c# - 使用诊断 C# 终止正在运行的最旧进程

html - 无法拆分行和列的 div