asp.net-mvc - asp.net/MVC 自定义模型验证属性不起作用

标签 asp.net-mvc razor unobtrusive-validation

(我已经取得了一些进展,但仍然无法正常工作,更新如下...)

我正在尝试实现旧的开始日期不大于结束日期的验证。这是我第一次尝试编写自定义验证属性。根据我在这里读到的内容,这就是我想出的......

自定义验证属性:

public class DateGreaterThanAttribute : ValidationAttribute
{
    private string _startDatePropertyName;

    public DateGreaterThanAttribute(string startDatePropertyName)
    {
        _startDatePropertyName = startDatePropertyName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyInfo = validationContext.ObjectType.GetProperty(_startDatePropertyName);
        if (propertyInfo == null)
        {
            return new ValidationResult(string.Format("Unknown property {0}", _startDatePropertyName));
        }
        var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
        if ((DateTime)value > (DateTime)propertyValue)
        {
            return ValidationResult.Success;
        }
        else
        {
            var startDateDisplayName = propertyInfo
                .GetCustomAttributes(typeof(DisplayNameAttribute), true)
                .Cast<DisplayNameAttribute>()
                .Single()
                .DisplayName;

            return new ValidationResult(validationContext.DisplayName + " must be later than " + startDateDisplayName + ".");
        }
    }
}

查看模型:

public class AddTranscriptViewModel : IValidatableObject
{
    ...

    [DisplayName("Class Start"), Required]
    [DataType(DataType.Date)]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    [RegularExpression(@"^(1[012]|0?[1-9])[/]([12][0-9]|3[01]|0?[1-9])[/](19|20)\d\d.*", ErrorMessage = "Date out of range.")]
    public DateTime? ClassStart { get; set; }

    [DisplayName("Class End"), Required]
    [DataType(DataType.Date)]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    [RegularExpression(@"^(1[012]|0?[1-9])[/]([12][0-9]|3[01]|0?[1-9])[/](19|20)\d\d.*", ErrorMessage = "Date out of range.")]
    [DateGreaterThan("ClassStart")]
    public DateTime? ClassEnd { get; set; }

    ...
}

前端相关部分:

@using (Html.BeginForm("AddManualTranscript", "StudentManagement", FormMethod.Post, new { id = "studentManagementForm", @class = "container form-horizontal" }))
{
    ...
    <div class="col-md-4" id="divUpdateStudent">@Html.Button("Save Transcript Information", "verify()", false, "button")</div>
    ...
    <div class="col-md-2">
        <div id="divClassStart">
            <div>@Html.LabelFor(d => d.ClassStart, new { @class = "control-label" })</div>
            <div>@Html.EditorFor(d => d.ClassStart, new { @class = "form-control" }) </div>
            <div>@Html.ValidationMessageFor(d => d.ClassStart)</div>
        </div>
    </div>

    <div class="col-md-2">
        <div id="divClassEnd">
            <div>@Html.LabelFor(d => d.ClassEnd, new { @class = "control-label" })</div>
            <div>@Html.EditorFor(d => d.ClassEnd, new { @class = "form-control" }) </div>
            <div>@Html.ValidationMessageFor(d => d.ClassEnd)</div>
        </div>
    </div>
    ...
}

<script type="text/javascript">
    ...
    function verify() {

        if ($("#StudentGrades").data("tGrid").total == 0) {
            alert("Please enter at least one Functional Area for the transcript grades.");
        }
        else {
            $('#studentManagementForm').trigger(jQuery.Event("submit"));
        }
    }
    ...
</script>

我看到的行为是表单上所有其他字段的所有其他验证(这些都是标准验证,如必需、StringLength 和正则表达式等)正在按预期工作:当我单击“保存”时按钮,未通过的字段会显示红色文本。我在 IsValid 代码中放置了一个断点,除非所有其他验证都通过,否则它不会命中。即使如此,如果验证检查失败,也不会停止发布。

进一步阅读后,我将以下内容添加到 Global.asax.cs 中:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DateGreaterThanAttribute), typeof(DataAnnotationsModelValidator));

但这没有什么区别。我还在回发函数中测试了ModelState.IsValid,结果是错误的。但对于其他验证者来说,如果永远无法做到这一点。我什至在标记中注意到,在生成页面时,在那些具有验证属性的字段上似乎创建了很多标记。这种魔力在哪里发生?为什么我的自定义验证器不在循环中?

那里有很多变化,但我这里所看到的似乎与我所看到的大致一致。我还阅读了一些有关在客户端注册验证器的内容,但这似乎仅适用于客户端验证,而不适用于提交/发布时的模型验证。如果答案是我的一些愚蠢的疏忽,我不会感到尴尬。经过大约一天的努力,我只需要它能够工作。

更新:

Rob 的回答引导我找到了下面评论中引用的链接,然后又引导我来到这里 client-side validation in custom validation attribute - asp.net mvc 4这让我来到这里https://thewayofcode.wordpress.com/tag/custom-unobtrusive-validation/

我在那里读到的内容与我所观察到的一致,标记中缺少一些东西,而且看起来作者概述了如何将其放入其中。因此,我将以下内容添加到我的验证属性类中:

public class DateGreaterThanAttribute : ValidationAttribute, IClientValidatable // IClientValidatable added here
...
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        //string errorMessage = this.FormatErrorMessage(metadata.DisplayName);
        string errorMessage = ErrorMessageString;

        // The value we set here are needed by the jQuery adapter
        ModelClientValidationRule dateGreaterThanRule = new ModelClientValidationRule
        {
            ErrorMessage = errorMessage,
            ValidationType = "dategreaterthan" // This is the name the jQuery adapter will use, "startdatepropertyname" is the name of the jQuery parameter for the adapter, must be LOWERCASE!
        };

        dateGreaterThanRule.ValidationParameters.Add("startdatepropertyname", _startDatePropertyName);

        yield return dateGreaterThanRule;
    }

并创建了这个 JavaScript 文件:

(function ($) {
    $.validator.addMethod("dategreaterthan", function (value, element, params) {
        console.log("method");
        return Date.parse(value) > Date.parse($(params).val());
    });

    $.validator.unobtrusive.adapters.add("dategreaterthan", ["startdatepropertyname"], function (options) {
        console.log("adaptor");
        options.rules["dategreaterthan"] = "#" + options.params.startdatepropertyname;
        options.messages["dategreaterthan"] = options.message;
    });
})(jQuery);

(注意 console.log 命中...我从来没有看到过这些。)

此后,当我浏览到 DataGreaterThanAttribute 构造函数和 GetClientValidationRules 中的页面时,我会收到点击。此外,ClassEnd 输入标记现在包含以下标记:

data-val-dategreaterthan="The field {0} is invalid." data-val-dategreaterthan-startdatepropertyname="ClassStart"

所以我越来越接近了。问题是,addMethod 和adapater.add 似乎没有完成它们的工作。当我使用以下命令在控制台中检查这些对象时:

$.validator.methods
$.validator.unobtrusive.adapters

...我添加的方法和适配器不存在。如果我在控制台中从 JavaScript 文件运行代码,它们就会被添加并存在。我还注意到,如果我通常使用以下命令检查不显眼的验证对象......

$("#studentManagementForm").data('unobtrusiveValidation')

...没有证据表明我的自定义验证。

正如我之前提到的,这里有很多例子,而且它们的做法似乎都有点不同,所以我仍在尝试一些不同的事情。但我真的希望以前打败过它的人能够出现并与我分享这把锤子。

如果我不能让它工作,我将戴上安全帽并编写一些黑客 JavaScript 来欺骗相同的功能。

最佳答案

我认为您的模型需要 IEnumerable

大约 4 年前,我不得不做类似的事情,如果这有帮助的话,我仍然有代码片段:

public class ResultsModel : IValidatableObject
{
    [Required(ErrorMessage = "Please select the from date")]
    public DateTime? FromDate { get; set; }

    [Required(ErrorMessage = "Please select the to date")]
    public DateTime? ToDate { get; set; }

    IEnumerable<ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
    {
        var result = new List<ValidationResult>();
        if (ToDate < FromDate)
        {
            var vr = new ValidationResult("The to date cannot be before the from date");
            result.Add(vr);
        }
        return result;
    }
}

关于asp.net-mvc - asp.net/MVC 自定义模型验证属性不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53542235/

相关文章:

c# - 如何在@Html.BeginForm中添加没有值的html属性

javascript - jquery 验证正则表达式方法与焦点上的 jquery 掩码冲突

html - IE7 并在 MS CRM 的 iframe 中发布表单 = 新窗口

c# - 提高网站数据库的搜索性能

visual-studio-2010 - Visual Studio 2010 陷入 MVC3 Razor 和 Azure 的解决方案

javascript - 重新解析从部分 View 创建的表单后,jQuery 提交事件未触发

jquery - 自定义 jQuery 不显眼验证的最小和最大错误消息

asp.net-mvc - 当我调试 ASP.NET MVC 应用程序时,为什么 Application_Start() 事件不触发?

c# - Visual Studio 2017在调试时尝试使用IP连接到本地Mysql

javascript - 如何在 javascript 代码中使用模型数据?