RequiredIf Атрибут условной проверки

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

Модель

public class MyInputModel 
{
    [Required]
    public int Id {get;set;}

    public string MyProperty1 {get;set;}
    public string MyProperty2 {get;set;}
    public bool MyProperty3 {get;set;}

}

Я хочу иметь по крайней мере prop1 prop2 prop3 со значением, и если prop3 является единственным заполненным значением, оно не должно равняться false. Как мне написать для этого атрибут (ы) валидации?

Спасибо за любую помощь!


person zSynopsis    schedule 12.09.2011    source источник
comment
Вы можете проверить следующий пост в блоге для примера реализации [RequiredIf] настраиваемого атрибута проверки. Он сравнивается с одним другим значением свойства, но вы можете легко настроить метод IsValid в соответствии со своими требованиями.   -  person Darin Dimitrov    schedule 12.09.2011


Ответы (6)


Вчера у меня была такая же проблема, но я сделал это очень чисто, что работает как для проверки на стороне клиента, так и на стороне сервера.

Условие: исходя из значения другого свойства в модели, вы хотите сделать другое свойство обязательным. Вот код:

public class RequiredIfAttribute : RequiredAttribute
{
  private String PropertyName { get; set; }
  private Object DesiredValue { get; set; }

  public RequiredIfAttribute(String propertyName, Object desiredvalue)
  {
    PropertyName = propertyName;
    DesiredValue = desiredvalue;
  }

  protected override ValidationResult IsValid(object value, ValidationContext context)
  {
    Object instance = context.ObjectInstance;
    Type type = instance.GetType();
    Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
    if (proprtyvalue.ToString() == DesiredValue.ToString())
    {
      ValidationResult result = base.IsValid(value, context);
      return result;
    }
    return ValidationResult.Success;
  }
}

PropertyName - это свойство, для которого вы хотите задать свое условие.
DesiredValue - это конкретное значение PropertyName (свойства), для которого необходимо проверить другое ваше свойство. для необходимого

Допустим, у вас есть следующее:

public enum UserType
{
  Admin,
  Regular
}

public class User
{
  public UserType UserType {get;set;}

  [RequiredIf("UserType",UserType.Admin,
              ErrorMessageResourceName="PasswordRequired", 
              ErrorMessageResourceType = typeof(ResourceString))]
  public string Password { get; set; }
}

Наконец, но не в последнюю очередь, зарегистрируйте адаптер для вашего атрибута, чтобы он мог выполнять проверку на стороне клиента (я поместил его в global.asax, Application_Start)

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),
                                                      typeof(RequiredAttributeAdapter));

РЕДАКТИРОВАТЬ

Некоторые люди жаловались, что клиентская сторона срабатывает независимо от того, что или не работает. Поэтому я изменил приведенный выше код, чтобы также выполнять условную проверку на стороне клиента с помощью Javascript. В этом случае вам не нужно регистрировать адаптер.

 public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
    {
        private String PropertyName { get; set; }
        private Object DesiredValue { get; set; }
        private readonly RequiredAttribute _innerAttribute;

        public RequiredIfAttribute(String propertyName, Object desiredvalue)
        {
            PropertyName = propertyName;
            DesiredValue = desiredvalue;
            _innerAttribute = new RequiredAttribute();
        }

        protected override ValidationResult IsValid(object value, ValidationContext context)
        {
            var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);

            if (dependentValue.ToString() == DesiredValue.ToString())
            {
                if (!_innerAttribute.IsValid(value))
                {
                    return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
                }
            }
            return ValidationResult.Success;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = ErrorMessageString,
                ValidationType = "requiredif",
            };
            rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
            rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;

            yield return rule;
        }
    }

И, наконец, javascript (объедините его и визуализируйте ... поместите его в отдельный файл сценария)

$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options) {
    options.rules['requiredif'] = options.params;
    options.messages['requiredif'] = options.message;
});

$.validator.addMethod('requiredif', function (value, element, parameters) {
    var desiredvalue = parameters.desiredvalue;
    desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
    var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
    var actualvalue = {}
    if (controlType == "checkbox" || controlType == "radio") {
        var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
        actualvalue = control.val();
    } else {
        actualvalue = $("#" + parameters.dependentproperty).val();
    }
    if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
        var isValid = $.validator.methods.required.call(this, value, element, parameters);
        return isValid;
    }
    return true;
});

Очевидно, вам нужно, чтобы ненавязчивый проверочный jQuery был включен в качестве требования

person Dan Hunex    schedule 12.04.2013
comment
@Dan Hunex: В MVC4 мне не удалось правильно работать на стороне клиента, и он запускает проверку независимо от того, что такое DesiredValue. Любая помощь, пожалуйста? - person Jack; 11.01.2015
comment
Могу я увидеть созданный вами атрибут - person Dan Hunex; 12.01.2015
comment
Та же проблема, что и у @ H.Johnson. Проверка на стороне клиента срабатывает несмотря ни на что. Любой способ решить эту проблему? - person Shiva Naru; 22.04.2015
comment
У меня такая же проблема. Он срабатывает несмотря ни на что. - person Steve Giordano; 23.04.2015
comment
Для тех из вас, кто считает, что это не работает на стороне клиента, я добавил более новую версию с javascript. - person Dan Hunex; 12.06.2015
comment
Интересно, что я редактировал без входа в систему ... хммм ... но хорошо, я надеюсь, что это поможет некоторым при поиске того же самого. - person Erik Simonic; 31.10.2015
comment
Фантастический ответ здесь, +1 от меня, но не могли бы вы объяснить, что следующие ErrorMessageResourceType = typeof(ResourceStrings)) ResourceStrings не распознаются на моем VS2013. - person Mike Upjohn; 09.11.2015
comment
Не обращайте на это внимания, я исправил! Спасибо! - person Mike Upjohn; 09.11.2015
comment
работает отлично. вы можете избежать включения вышеуказанного сценария проверки и повторно использовать уже доступную обязательную проверку на стороне клиента, установив ErrorMessage = string.Format("{0} is required.", metadata.DisplayName), validationType = "required" в RequiredIfAttribute.cs - person cronixis; 02.04.2016
comment
@cronixis Вот сработало! Спасибо - person LP13; 12.05.2016
comment
как установить переключатель, если текстовое поле не пусто [RequiredIf (SomeTextBox, что здесь говорить, ErrorMessage = Message)] - person CoolArchTek; 10.06.2016
comment
Я хотел бы отметить, что если вас беспокоит локализация и вам нужны стандартные сообщения проверки RequiredAttribute, вы можете просто установить ErrorMessage = _innerAttribute.FormatErrorMessage (metadata.GetDisplayName ()) в GetClientValidationRules. - person Miguel A. Arilla; 17.08.2016
comment
Так что для меня это продолжало возвращаться. Это поле является обязательным в сводке, и я не мог показать правильное сообщение. Я думаю, что есть несоответствие, вызвав существующий метод required, но установив сообщение на новый метод requiredif. Что я сделал, так это поменял местами две строки внутри сравнения if check (ту, которая с операторами $.trim) и заменил их кодом внутри метода required внутри jquery.validate.js. В основном сделайте то же самое, что и метод required, но внутри метода requiredif, чтобы отображалось правильное сообщение. - person Evan; 05.10.2016
comment
@DanHunex Не могли бы вы объяснить, как использовать написанный вами JS-код? Не могли бы вы привести пример, где именно это писать и как это будет использоваться? - person Misha Zaslavsky; 08.01.2017
comment
@MishaZaslavsky Как я уже сказал, поместите его в отдельный файл, объедините его, и он будет работать автоматически, когда вы используете атрибут RequiredIf в своих классах модели. Как связать ?! вы можете ознакомиться с этим tutorialsteacher.com/mvc/scriptbundle-mvc - person Dan Hunex; 10.01.2017
comment
Это отличный ответ, спасибо, что сэкономили мне часы на разработку самого кода - person johnc; 11.01.2017
comment
@MikeUpjohn Не могли бы вы рассказать мне, как вы решили ErrorMessageResourceType проблему? Мой не работает. - person John Adam; 18.06.2017
comment
Мне пришлось добавить || "false", чтобы заставить RequiredIf (checkbox) работать: if (controlType == "checkbox" || controlType == "radio") { var control = $("input[id$='" + parameters.dependentproperty + "']:checked"); actualvalue = control.val() || "false"; - person devio; 05.12.2018
comment
@devio Да. Вы можете сделать это. Я написал это на основе чекбокса. Если вам нужен другой тип управления, вы можете добавить дополнительные условия - person Dan Hunex; 06.12.2018
comment
Тип System.Web.Mvc.RequiredAttributeAdapter должен иметь общедоступный конструктор, который принимает три параметра типов: System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext и RequiredIfAttribute Имя параметра: adapterType - person Joseph Norris; 26.07.2019
comment
Правильный. Но как я могу работать с настраиваемым свойством с условием. Я не получаю PropertyName из контекста в [dependentproperty] .. Это нормально. Я изменил код и напрямую назначил PropertyName на [dependentproperty], но затем в jquery поле с тем же именем недоступно в контексте html. Таким образом, актуальное значение все еще не определено, - person SPnL; 01.04.2020
comment
@DanHunex Я должен реализовать этот тип проверки в ASP.NET MVC Core 3.1. Есть идеи, как реализовать? - person Simant; 03.12.2020
comment
@Simant Вам следует использовать аналогичный подход. Документация здесь docs.microsoft.com / en-us / aspnet / core / mvc / models / дает хороший пример настраиваемой проверки. - person Dan Hunex; 04.12.2020

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

Используя его, вы можете добиться желаемого результата следующим образом:

[RequiredIf("MyProperty2 == null && MyProperty3 == false")]
public string MyProperty1 { get; set; }

[RequiredIf("MyProperty1 == null && MyProperty3 == false")]
public string MyProperty2 { get; set; }

[AssertThat("MyProperty1 != null || MyProperty2 != null || MyProperty3 == true")]
public bool MyProperty3 { get; set; }

Дополнительную информацию о библиотеке ExpressiveAnnotations можно найти здесь. Это должно упростить многие случаи декларативной проверки без необходимости написания дополнительных атрибутов для конкретного случая или использования императивного способа проверки внутри контроллеров.

person jwaliszko    schedule 14.08.2013
comment
Огромное спасибо за эту библиотеку. С точки зрения расширяемости он превосходит все остальные. - person Rich Bryant; 11.11.2014
comment
Я применил все шаги, упомянутые в github.com/JaroslawWaliszko/ExpressiveAnnotations, но не сработал для меня, давая следующая ошибка: Тип System.Web.Mvc.RequiredAttributeAdapter должен иметь открытый конструктор, который принимает три параметра типов System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext и ExpressiveAnnotations.Attributes.RequiredIfAttribute Имя параметра: adapterType - person Jack; 11.01.2015
comment
@ Х. Джонсон: Это исключение маловероятно. Я предполагаю, что в вашем коде есть проблема (возможно, у вас есть неоднозначность типов - вы уверены, что в вашем Global.asax вы зарегистрировали адаптеры для атрибутов из соответствующего пространства имен, то есть ExpressiveAnnotations.Attributes, а не какие-либо другие?). Чтобы помочь вам, мне нужно больше информации, выше - меньше. Наконец, взгляните на образец проекта на github и попробуйте исследуйте, в чем разница. - person jwaliszko; 12.01.2015
comment
@ H.Johnson: объявление 1) MvcUnobtrusiveValidatorProvider.dll должен автоматически добавляться NuGet к вашим ссылкам. Если по какой-то причине его нет - добавьте ссылку вручную. ad 2) Чтобы проверка на стороне клиента работала, несмотря на ExpressiveAnnotations.dll, здесь также должен быть упомянутый MvcUnobtrusiveValidatorProvider.dll. Более того, expressive.annotations.validate.js должен быть включен в комплект ниже файлов проверки jquery и добавлен на указанную страницу (см. Образец проекта). - person jwaliszko; 14.01.2015
comment
@JaroslawWaliszko: Спасибо за вашу любезную помощь. На самом деле ваше сообщение воодушевило меня, и я попробовал еще раз. Я не знаю, в чем была проблема, но с последней попытки мне удалось решить ее на стороне сервера и клиента. Это просто замечательно, просто и очень гибко. Я искал на многих веб-сайтах. Большое спасибо за ваш хороший пример и помощь. Проголосовал;) - person Jack; 14.01.2015
comment
С другой стороны, для моего предыдущего сообщения мне удалось найти ExpressiveAnnotations.MvcUnobtrusiveValidatorProvider.dll из проекта, который я попробовал первым. Еще раз большое спасибо за ваше внимание. - person Jack; 14.01.2015
comment
@ Х.Джонсон: Нет проблем, я рад, что это помогло;] - person jwaliszko; 14.01.2015
comment
Просто голова вверх, для этого требуется bootstrap 3.0.1.1 или выше. Я не могу его использовать, потому что мы используем Bootstrap 3.0.0. - person Josh Noe; 05.01.2016
comment
Большое вам спасибо за это ... мы все должны проголосовать за это. Это решает те сложные задачи, которые требуются при проверке :) - person Jeremiah Flaga; 17.07.2018
comment
Эта библиотека предназначена только для ASP.NET, а не для ASP.NET Core? - person Sarah; 05.05.2020

Я заставил его работать на ASP.NET MVC 5

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

Примечания

  • работал над MVC 5 как на стороне сервера, так и на стороне клиента: D
  • Я вообще не устанавливал библиотеку "ExpressiveAnnotations".
  • Я беру исходный код от "@Dan Hunex", найдите его выше

Советы по исправлению этой ошибки

«Тип System.Web.Mvc.RequiredAttributeAdapter должен иметь открытый конструктор, который принимает три параметра типов: System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext и ExpressiveAnnotations.Attributes.RequiredIfAttribute Имя параметра: adapterType»

Совет №1: убедитесь, что вы наследуете от ValidationAttribute, а не от RequiredAttribute.

 public class RequiredIfAttribute : ValidationAttribute, IClientValidatable { ...}

Совет № 2: ИЛИ удалите всю эту строку из Global.asax. В новой версии кода она вообще не нужна (после редактирования @Dan_Hunex) , и да, эта строчка была обязательной в старой версии ...

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredAttributeAdapter));

Советы по работе с частью кода Javascript

1- поместите код в новый файл js (например, requiredIfValidator.js)

2- деформировать код внутри $ (document) .ready (function () {........});

3- включите наш файл js после включения библиотек проверки JQuery, так что теперь он выглядит так:

@Scripts.Render("~/bundles/jqueryval")
<script src="~/Content/JS/requiredIfValidator.js"></script>

4- Отредактируйте код C #

от

rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);

to

rule.ValidationParameters["dependentproperty"] = PropertyName;

и из

if (dependentValue.ToString() == DesiredValue.ToString())

to

if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())

Весь мой код запущен и работает

Global.asax

Здесь нечего добавить, держите его в чистоте

requiredIfValidator.js

создайте этот файл в ~ / content или в папке ~ / scripts

    $.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options)
{
    options.rules['requiredif'] = options.params;
    options.messages['requiredif'] = options.message;
});


$(document).ready(function ()
{

    $.validator.addMethod('requiredif', function (value, element, parameters) {
        var desiredvalue = parameters.desiredvalue;
        desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
        var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
        var actualvalue = {}
        if (controlType == "checkbox" || controlType == "radio") {
            var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
            actualvalue = control.val();
        } else {
            actualvalue = $("#" + parameters.dependentproperty).val();
        }
        if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
            var isValid = $.validator.methods.required.call(this, value, element, parameters);
            return isValid;
        }
        return true;
    });
});

_Layout.cshtml или представление

@Scripts.Render("~/bundles/jqueryval")
<script src="~/Content/JS/requiredIfValidator.js"></script>

Класс RequiredIfAttribute.cs

создайте его где-нибудь в вашем проекте, например в ~ / models / customValidation /

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Your_Project_Name.Models.CustomValidation
{
    public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
    {
        private String PropertyName { get; set; }
        private Object DesiredValue { get; set; }
        private readonly RequiredAttribute _innerAttribute;

        public RequiredIfAttribute(String propertyName, Object desiredvalue)
        {
            PropertyName = propertyName;
            DesiredValue = desiredvalue;
            _innerAttribute = new RequiredAttribute();
        }

        protected override ValidationResult IsValid(object value, ValidationContext context)
        {
            var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);

            if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())
            {
                if (!_innerAttribute.IsValid(value))
                {
                    return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
                }
            }
            return ValidationResult.Success;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = ErrorMessageString,
                ValidationType = "requiredif",
            };
            rule.ValidationParameters["dependentproperty"] = PropertyName;
            rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;

            yield return rule;
        }
    }
}

Модель

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using Your_Project_Name.Models.CustomValidation;

namespace Your_Project_Name.Models.ViewModels
{

    public class CreateOpenActivity
    {
        public Nullable<int> ORG_BY_CD { get; set; }

        [RequiredIf("ORG_BY_CD", "5", ErrorMessage = "Coordinator ID is required")] // This means: IF 'ORG_BY_CD' is equal 5 (for the example)  > make 'COR_CI_ID_NUM' required and apply its all validation / data annotations
        [RegularExpression("[0-9]+", ErrorMessage = "Enter Numbers Only")]
        [MaxLength(9, ErrorMessage = "Enter a valid ID Number")]
        [MinLength(9, ErrorMessage = "Enter a valid ID Number")]
        public string COR_CI_ID_NUM { get; set; }
    }
}

Обзор

На самом деле здесь нечего отметить ...

    @model Your_Project_Name.Models.ViewModels.CreateOpenActivity
@{
    ViewBag.Title = "Testing";
}

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>CreateOpenActivity</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.ORG_BY_CD, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ORG_BY_CD, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ORG_BY_CD, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.COR_CI_ID_NUM, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.COR_CI_ID_NUM, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.COR_CI_ID_NUM, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Я могу загрузить образец проекта для этого позже ...

Надеюсь, это было полезно

Спасибо

person Adel Mourad    schedule 01.05.2017
comment
У меня возникла проблема с возвращением сообщений об ошибках клиента, поскольку поле [object Object] недействительно. Если вы столкнулись с таким же, замените ErrorMessage = ErrorMessageString, на ErrorMessage = ErrorMessage ?? string.Format(ErrorMessageString, metadata.DisplayName), - person ScoobyDrew18; 21.05.2019
comment
@Adel Mourad Мне нужно реализовать аналогичную проверку в ASP.NET MVC Core 3.1. У вас есть идеи, как реализовать этот код в asp.net MVC Core? - person Simant; 03.12.2020
comment
@Simant Вы часто включаете / выключаете требуемую проверку вручную, используя C # и JS. Для C # используйте ModelState.Remove (PropName), чтобы удалить проверку из некоторого свойства перед вызовом ModelState.IsValid .... - person Adel Mourad; 04.12.2020

Если вы попытаетесь использовать «ModelState.Remove» или «ModelState [« Prop »]. Errors.Clear ()», «ModelState.IsValid» по-прежнему вернет false.

Почему бы просто не удалить стандартную «Обязательную» аннотацию из модели и не выполнить пользовательскую проверку перед «ModelState.IsValid» в действии «Post» контроллера? Нравится:

if (!String.IsNullOrEmpty(yourClass.Property1) && String.IsNullOrEmpty(yourClass.dependantProperty))            
            ModelState.AddModelError("dependantProperty", "It´s necessary to select some 'dependant'.");
person Jader de Alencar Rodrigues    schedule 25.08.2016
comment
Я нашел это решение самым простым. Ошибка, возникшая таким образом, даже отображается вместе с ошибками, вызванными встроенным атрибутом [Required]. Спасибо! - person GuiRitter; 23.07.2020

Расширяя примечания от Адель Мурад и Дэна Хунекса, я изменил код, чтобы предоставить пример, который принимает только значения, не совпадающие с заданным значением.

Я также обнаружил, что мне не нужен JavaScript.

Я добавил в свою папку Models следующий класс:

public class RequiredIfNotAttribute : ValidationAttribute, IClientValidatable
{
    private String PropertyName { get; set; }
    private Object InvalidValue { get; set; }
    private readonly RequiredAttribute _innerAttribute;

    public RequiredIfNotAttribute(String propertyName, Object invalidValue)
    {
        PropertyName = propertyName;
        InvalidValue = invalidValue;
        _innerAttribute = new RequiredAttribute();
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);

        if (dependentValue.ToString() != InvalidValue.ToString())
        {
            if (!_innerAttribute.IsValid(value))
            {
                return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
            }
        }
        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessageString,
            ValidationType = "requiredifnot",
        };
        rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
        rule.ValidationParameters["invalidvalue"] = InvalidValue is bool ? InvalidValue.ToString().ToLower() : InvalidValue;

        yield return rule;
    }

Мне не нужно было вносить какие-либо изменения в свое представление, но я внес изменения в свойства моей модели:

    [RequiredIfNot("Id", 0, ErrorMessage = "Please select a Source")]
    public string TemplateGTSource { get; set; }

    public string TemplateGTMedium
    {
        get
        {
            return "Email";
        }
    }

    [RequiredIfNot("Id", 0, ErrorMessage = "Please enter a Campaign")]
    public string TemplateGTCampaign { get; set; }

    [RequiredIfNot("Id", 0, ErrorMessage = "Please enter a Term")]
    public string TemplateGTTerm { get; set; }

Надеюсь это поможет!

person Amy Gray    schedule 31.10.2017

Основное отличие от других решений здесь заключается в том, что это повторно использует логику в RequiredAttribute на стороне сервера и использует свойство depends метода проверки depends на стороне клиента:

public class RequiredIf : RequiredAttribute, IClientValidatable
{
    public string OtherProperty { get; private set; }
    public object OtherPropertyValue { get; private set; }

    public RequiredIf(string otherProperty, object otherPropertyValue)
    {
        OtherProperty = otherProperty;
        OtherPropertyValue = otherPropertyValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherProperty);
        if (otherPropertyInfo == null)
        {
            return new ValidationResult($"Unknown property {OtherProperty}");
        }

        object otherValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
        if (Equals(OtherPropertyValue, otherValue)) // if other property has the configured value
            return base.IsValid(value, validationContext);

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule();
        rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
        rule.ValidationType = "requiredif"; // data-val-requiredif
        rule.ValidationParameters.Add("other", OtherProperty); // data-val-requiredif-other
        rule.ValidationParameters.Add("otherval", OtherPropertyValue); // data-val-requiredif-otherval

        yield return rule;
    }
}

$.validator.unobtrusive.adapters.add("requiredif", ["other", "otherval"], function (options) {
    var value = {
        depends: function () {
            var element = $(options.form).find(":input[name='" + options.params.other + "']")[0];
            return element && $(element).val() == options.params.otherval;
        }
    }
    options.rules["required"] = value;
    options.messages["required"] = options.message;
});
person glut    schedule 09.01.2017