RequiredIf Атрибут условной проверки
Я искал несколько советов о том, как лучше всего реализовать атрибут проверки, который делает следующее.
Model
public class MyInputModel
{
[Required]
public int Id {get;set;}
public string MyProperty1 {get;set;}
public string MyProperty2 {get;set;}
public bool MyProperty3 {get;set;}
}
Я хочу иметь atleast prop1 prop2 prop3 со значением, и если только prop3 является единственным значением, которое оно заполняет, оно не должно быть равно false.
Как я могу написать атрибут проверки (s?) Для этого?
Спасибо за любую помощь!
Ответы
Ответ 1
Вы можете проверить следующее сообщение в блоге для примерной реализации атрибута [RequiredIf]
custom validation. Он сравнивается с одним другим значением свойства, но вы можете легко настроить метод IsValid
для соответствия вашим требованиям.
Ответ 2
У меня была такая же проблема вчера, но я сделал это очень простым способом, который работает как на стороне клиента, так и на стороне сервера.
Условие. Основываясь на значении другого свойства в модели, вы хотите сделать еще одно свойство. Вот код
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 (скомпоновать его и renderit... поместить его в свой собственный script файл)
$.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 как требование
Ответ 3
Я знаю, что тема была задана некоторое время назад, но недавно я столкнулся с подобной проблемой и нашел еще одно, но, на мой взгляд, более полное решение. Я решил реализовать механизм, который предоставляет условные атрибуты для вычисления результатов валидации на основе других значений свойств и отношений между ними, которые определены в логических выражениях.
Используя его, вы можете получить результат, о котором вы спрашивали, следующим образом:
[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 можно найти здесь. Он должен упростить многие декларативные случаи проверки без необходимости писать дополнительные атрибуты для конкретного случая или использовать императивный способ проверки внутри контроллеров.
Ответ 4
Я получил его для работы над 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- Редактировать код С#
от
rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
к
rule.ValidationParameters["dependentproperty"] = PropertyName;
и из
if (dependentValue.ToString() == DesiredValue.ToString())
к
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 или View
@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>
}
Я могу загрузить образец проекта для этого позже...
Надеюсь, это было полезно
Спасибо
Ответ 5
Если вы попытаетесь использовать "ModelState.Remove" или "ModelState [" Prop "]. Errors.Clear()" ModelState.IsValid "stil возвращает false.
Почему бы просто не удалить аннотацию по умолчанию "Обязательный" из модели и сделать свою собственную проверку перед "ModelState.IsValid" в действии Controller "Post"? Вот так:
if (!String.IsNullOrEmpty(yourClass.Property1) && String.IsNullOrEmpty(yourClass.dependantProperty))
ModelState.AddModelError("dependantProperty", "It´s necessary to select some 'dependant'.");
Ответ 6
Основное отличие от других решений заключается в том, что этот повторяет логику в RequiredAttribute
на стороне сервера и использует свойство required
validation method 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;
});
Ответ 7
Расширяясь в заметках от Аделя Мурада и Дэна Хунэкса, я внес изменения в код, чтобы привести пример, который принимает только значения, которые не соответствуют соответствуют заданному значению.
Я также обнаружил, что мне не нужен JavaScript.
Я добавил следующий класс в папку Моды:
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; }
Надеюсь, это поможет!
Ответ 8
В модели просмотра для каждого поля, которое вы хотите проверить в соответствии со значением другого поля, выполните следующее:
public string FieldName { get; set; }
[RequiredIf("FieldName", ConditionTypes.Equals, condition)]
public string FieldName1 { get; set; }