MVC 3.0 - 不显眼的客户端验证不适用于自定义属性

发布于 2025-01-07 12:46:32 字数 4058 浏览 0 评论 0原文

我是 mvc 3.0 和 jquery 的新手。我正在尝试使用自定义的验证属性在客户端和服务器端验证“日期”。它在服务器端工作正常,但无法使其在客户端工作。

我使用 mvc 3.0、jquery、IE 7.0。 在 MVC 3.0 中,我们需要在 global.ascx 中注册任何东西吗?

请让我知道我错在哪里。 TIA。

这是我的代码:

验证属性

 public class FutureDateAttribute : ValidationAttribute, IClientValidatable
 {
        private const string DateFormat = "mm/dd/yyyy";
        private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

        public DateTime Min { get; set; }
        public DateTime Max { get; set; }

        public FutureDateAttribute(string min)
            : base(DefaultErrorMessage)
        {
            Min = ParseDate(min);
            Max = DateTime.Now;
        }

        public override bool IsValid(object value)
        {
            if (value == null || !(value is DateTime))
            { return true; }
            DateTime dateValue = (DateTime)value;
            return Min <= dateValue && dateValue <= Max;
        }

        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
        }

        public class ModelClientValidationFutureDateRule : ModelClientValidationRule
        {
            public ModelClientValidationFutureDateRule(string errorMessage,
                DateTime min)
            {
                ErrorMessage = errorMessage;
                ValidationType = "futuredate";
                ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
                ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");
            }
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
            yield return rule;
        }

jquery

(function ($) {
$.validator.addMethod('futuredate', function (value, element, param) {
    if (!value) return false;
    var min = $(param.min).val();
    var max = $(param.max).val();
    if (value < min || value > max) {
        return false;
    }
    return true;
});

$.validator.unobtrusive.adapters.add(
  'futuredate', ['min', 'max'],
  function (options) {
      var params = {
          min: options.params.min,
          max: options.params.max
      };

      options.rules['futuredate'] = params;
      if (options.message) {
          options.messages['futuredate'] = options.message;
      }
  });
} (jQuery)); 

参考

<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
 ///reference path="jquery-1.5.1.min.js" />
 ///reference path="jquery.validate.js" />
 ///reference path="jquery-ui-1.8.11.js" />
  ///reference path="jquery.validate.unobtrusive.min.js" />
 ///reference path="jquery.validate-vsdoc.js" />

模型:

[DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }

I am new to mvc 3.0 and jquery. i am trying to validate the 'date' both at client side and server side using customized validation attributes. It is working fine at server side, but am not able to make it work at client side.

am using mvc 3.0, jquery, IE 7.0.
do we need to register any thing in global.ascx in MVC 3.0?

Please let me know where I am wrong.
TIA.

Here is my code:

Validation Attribute

 public class FutureDateAttribute : ValidationAttribute, IClientValidatable
 {
        private const string DateFormat = "mm/dd/yyyy";
        private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

        public DateTime Min { get; set; }
        public DateTime Max { get; set; }

        public FutureDateAttribute(string min)
            : base(DefaultErrorMessage)
        {
            Min = ParseDate(min);
            Max = DateTime.Now;
        }

        public override bool IsValid(object value)
        {
            if (value == null || !(value is DateTime))
            { return true; }
            DateTime dateValue = (DateTime)value;
            return Min <= dateValue && dateValue <= Max;
        }

        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
        }

        public class ModelClientValidationFutureDateRule : ModelClientValidationRule
        {
            public ModelClientValidationFutureDateRule(string errorMessage,
                DateTime min)
            {
                ErrorMessage = errorMessage;
                ValidationType = "futuredate";
                ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
                ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");
            }
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
            yield return rule;
        }

jquery

(function ($) {
$.validator.addMethod('futuredate', function (value, element, param) {
    if (!value) return false;
    var min = $(param.min).val();
    var max = $(param.max).val();
    if (value < min || value > max) {
        return false;
    }
    return true;
});

$.validator.unobtrusive.adapters.add(
  'futuredate', ['min', 'max'],
  function (options) {
      var params = {
          min: options.params.min,
          max: options.params.max
      };

      options.rules['futuredate'] = params;
      if (options.message) {
          options.messages['futuredate'] = options.message;
      }
  });
} (jQuery)); 

References

<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
 ///reference path="jquery-1.5.1.min.js" />
 ///reference path="jquery.validate.js" />
 ///reference path="jquery-ui-1.8.11.js" />
  ///reference path="jquery.validate.unobtrusive.min.js" />
 ///reference path="jquery.validate-vsdoc.js" />

Model:

[DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情何以堪。 2025-01-14 12:46:32

我可以看到您的代码有几个问题。第一个:

ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");

必须是:

ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");

因为 mm 表示分钟而不是几个月。

同样的评论:

private const string DateFormat = "mm/dd/yyyy";

这必须是:

private const string DateFormat = "MM/dd/yyyy";

在客户端,您也有一些问题。在您的 futuredate 验证方法中,您似乎正在执行 var min = $(param.min).val(); ,这会转换为 var min = $(' 12/31/1899').val(); 这显然没有多大意义。您必须将这些值解析为 javascript Date 实例,然后才能进行比较他们。

所以这就是我建议你的:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
    (function ($) {
        var parseDate = function (str) {
            var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
            return (m) ? new Date(m[3], m[1] - 1, m[2]) : null;
        };

        $.validator.addMethod('futuredate', function (value, element, param) {
            if (!value) return false;

            var min = parseDate(param.min);
            var max = parseDate(param.max);
            var current = parseDate(value);

            if (min == null || max == null || current == null) {
                return false;
            }

            return (current >= min && current <= max);
        });

        $.validator.unobtrusive.adapters.add('futuredate', ['min', 'max'], function (options) {
            var params = {
                min: options.params.min,
                max: options.params.max
            };

            options.rules['futuredate'] = params;
            if (options.message) {
                options.messages['futuredate'] = options.message;
            }
        });
    } (jQuery));
</script>

@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.AssignedDate)
    @Html.EditorFor(x => x.AssignedDate)
    @Html.ValidationMessageFor(x => x.AssignedDate)
    <button type="submit">OK</button>
}

这是我用于测试用例的验证属性的完整代码:

public class FutureDateAttribute : ValidationAttribute, IClientValidatable
{
    private const string DateFormat = "MM/dd/yyyy";
    private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

    public DateTime Min { get; set; }
    public DateTime Max { get; set; }

    public FutureDateAttribute(string min)
        : base(DefaultErrorMessage)
    {
        Min = ParseDate(min);
        Max = DateTime.Now;
    }

    public override bool IsValid(object value)
    {
        if (value == null || !(value is DateTime))
        { return true; }
        DateTime dateValue = (DateTime)value;
        return Min <= dateValue && dateValue <= Max;
    }

    private static DateTime ParseDate(string dateValue)
    {
        return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
    }

    public class ModelClientValidationFutureDateRule : ModelClientValidationRule
    {
        public ModelClientValidationFutureDateRule(string errorMessage,
            DateTime min)
        {
            ErrorMessage = errorMessage;
            ValidationType = "futuredate";
            ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
            ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");
        }
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
        yield return rule;
    }
}

以及模型:

public class MyViewModel
{
    [DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }
}

和控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel
        {
            AssignedDate = DateTime.Now.AddDays(2)
        });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

There are a couple of issues I can see with your code. The first one:

ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");

must really be:

ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");

because mm means minutes not months.

Same remark for:

private const string DateFormat = "mm/dd/yyyy";

which must be:

private const string DateFormat = "MM/dd/yyyy";

On the client side you have a couple of issues as well. In your futuredate validation method you seem to be doing var min = $(param.min).val(); which translates to var min = $('12/31/1899').val(); which obviously doesn't make much sense. You will have to parse those values into javascript Date instances before being able to compare them.

So here's what I would suggest you:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
    (function ($) {
        var parseDate = function (str) {
            var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
            return (m) ? new Date(m[3], m[1] - 1, m[2]) : null;
        };

        $.validator.addMethod('futuredate', function (value, element, param) {
            if (!value) return false;

            var min = parseDate(param.min);
            var max = parseDate(param.max);
            var current = parseDate(value);

            if (min == null || max == null || current == null) {
                return false;
            }

            return (current >= min && current <= max);
        });

        $.validator.unobtrusive.adapters.add('futuredate', ['min', 'max'], function (options) {
            var params = {
                min: options.params.min,
                max: options.params.max
            };

            options.rules['futuredate'] = params;
            if (options.message) {
                options.messages['futuredate'] = options.message;
            }
        });
    } (jQuery));
</script>

@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.AssignedDate)
    @Html.EditorFor(x => x.AssignedDate)
    @Html.ValidationMessageFor(x => x.AssignedDate)
    <button type="submit">OK</button>
}

and here's the full code of the validation attribute I have used for my test case:

public class FutureDateAttribute : ValidationAttribute, IClientValidatable
{
    private const string DateFormat = "MM/dd/yyyy";
    private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

    public DateTime Min { get; set; }
    public DateTime Max { get; set; }

    public FutureDateAttribute(string min)
        : base(DefaultErrorMessage)
    {
        Min = ParseDate(min);
        Max = DateTime.Now;
    }

    public override bool IsValid(object value)
    {
        if (value == null || !(value is DateTime))
        { return true; }
        DateTime dateValue = (DateTime)value;
        return Min <= dateValue && dateValue <= Max;
    }

    private static DateTime ParseDate(string dateValue)
    {
        return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
    }

    public class ModelClientValidationFutureDateRule : ModelClientValidationRule
    {
        public ModelClientValidationFutureDateRule(string errorMessage,
            DateTime min)
        {
            ErrorMessage = errorMessage;
            ValidationType = "futuredate";
            ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
            ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");
        }
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
        yield return rule;
    }
}

And the model:

public class MyViewModel
{
    [DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }
}

and the controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel
        {
            AssignedDate = DateTime.Now.AddDays(2)
        });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文