Не работает атрибут проверки пользовательской модели asp.net/MVC - PullRequest
0 голосов
/ 29 ноября 2018

(я добился некоторого прогресса, но все еще не работает, обновления ниже ...)

Я пытаюсь реализовать, что старая дата начала не превышает проверку даты окончания,Это первый раз, когда я пытался написать собственный атрибут проверки.Основываясь на том, что я здесь прочитал, вот что я придумал ...

настраиваемый атрибут проверки:

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>

Я наблюдаю поведение, которое заключается в том, что все остальные проверки во всех других полях формы, которые являются стандартными проверками, такими как Required, StringLength,и RegularExpression и т. д. работают должным образом: когда я нажимаю кнопку «Сохранить», красный текст отображается для тех полей, которые не проходят.Я установил точку останова в своем коде IsValid, и он не срабатывает, если не пройдены все остальные проверки.И даже тогда, если проверка не пройдена, это не остановит публикацию.

Дальнейшее чтение побудило меня добавить в Global.asax.cs следующее:

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

Но этоне имеет значения.Я также протестировал ModelState.IsValid в функции обратной передачи, и это было ложно.Но для других валидаторов, если никогда не зашел так далеко.Я даже заметил в разметке, что создается много разметки в тех полях, которые имеют атрибуты проверки при создании страницы.Где происходит это волшебство и почему мой пользовательский валидатор выходит из цикла?

Существует много вариаций, но то, что у меня здесь есть, в целом соответствует тому, что я вижу.Я также читал о регистрации валидаторов на стороне клиента, но, похоже, это относится только к валидации на стороне клиента, а не к валидации модели при отправке / публикации.Я не буду смущен, если ответ будет какой-то глупой оплошностью с моей стороны.Приблизительно после одного дня этого мне просто нужно, чтобы оно заработало.

Обновление:

Ответ Роба привел меня к ссылке, указанной в моем комментарии ниже, которая затем привеламеня здесь проверка на стороне клиента в пользовательском атрибуте проверки - 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, чтобы подделать ту же функциональность.

1 Ответ

0 голосов
/ 29 ноября 2018

Я думаю, вам нужно 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...