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와 같지 않아야합니다. 이것에 대한 유효성 검사 속성을 작성하려면 어떻게해야합니까?
도움을 주셔서 감사합니다!
어제 같은 문제가 있었지만 클라이언트 측과 서버 측 유효성 검사 모두에서 작동하는 매우 깨끗한 방식으로 처리했습니다.
조건 : 모델의 다른 속성 값을 기준으로 다른 속성을 필요로합니다. 다음은 코드입니다.
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));
편집 됨
어떤 사람들은 클라이언트 측이 작동하지 않거나 작동하지 않더라도 발생한다고 불평했습니다. 그래서 위의 코드를 수정하여 자바 스크립트로 조건부 클라이언트 측 유효성 검사도 수행했습니다. 이 경우 어댑터를 등록 할 필요가 없습니다.
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;
}
}
그리고 마지막으로 자바 스크립트 (번들 및 렌더링 ... 자체 스크립트 파일에 넣습니다)
$.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가 필요합니다.
나는 그 주제가 얼마 전에 질문되었다는 것을 알고 있지만 최근에 비슷한 문제에 직면하여 또 다른 문제를 발견했지만 내 의견으로는 더 완전한 해결책을 찾았습니다. 조건부 속성을 제공하는 메커니즘을 구현하여 논리식에 정의 된 다른 속성 값과 이들 간의 관계를 기반으로 유효성 검사 결과를 계산하기로 결정했습니다.
이를 사용하면 다음과 같은 방식으로 요청한 결과를 얻을 수 있습니다.
[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 라이브러리에 대한 자세한 정보는 여기에서 찾을 수 있습니다 . 추가 사례 별 속성을 작성하거나 컨트롤러 내부에서 명령 적 유효성 검사 방법을 사용할 필요없이 많은 선언적 유효성 검사 사례를 단순화해야합니다.
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 : ' RequiredAttribute '가 아닌 ' ValidationAttribute ' 에서 상속하고 있는지 확인하십시오 .
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- JQuery 유효성 검사 라이브러리를 포함시킨 후 js 파일을 포함하면 이제 다음과 같이 보입니다.
@Scripts.Render("~/bundles/jqueryval")
<script src="~/Content/JS/requiredIfValidator.js"></script>
4- C # 코드 편집
...에서
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 또는보기
@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>
}
나중에이를 위해 프로젝트 샘플을 업로드 할 수 있습니다 ...
도움이 되었기를 바랍니다.
감사합니다
Adel Mourad 및 Dan Hunex의 메모를 확장 하여 주어진 값과 일치 하지 않는 값만 허용하는 예제를 제공하기 위해 코드를 수정했습니다 .
또한 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; }
도움이 되었기를 바랍니다!
"ModelState.Remove"또는 "ModelState ["Prop "]. Errors.Clear ()"를 사용하려고하면 "ModelState.IsValid"stil이 false를 반환합니다.
Why not just removing the default "Required" Annotation from Model and make your custom validation before the "ModelState.IsValid" on Controller 'Post' action? Like this:
if (!String.IsNullOrEmpty(yourClass.Property1) && String.IsNullOrEmpty(yourClass.dependantProperty))
ModelState.AddModelError("dependantProperty", "It´s necessary to select some 'dependant'.");
The main difference from other solutions here is that this one reuses logic in RequiredAttribute
on the server side, and uses required
's validation method depends
property on the client side:
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;
});
ReferenceURL : https://stackoverflow.com/questions/7390902/requiredif-conditional-validation-attribute
'programing' 카테고리의 다른 글
Django-AttributeError 'User'객체에는 'backend'속성이 없습니다 (하지만… (0) | 2021.01.17 |
---|---|
SDK 도구, 버전 12에서 Android 에뮬레이터 시작 (0) | 2021.01.17 |
androidX 라이브러리에없는 BottomSheetBehavior (0) | 2021.01.16 |
jquery로 요소의 클래스 이름을 변경하는 방법 (0) | 2021.01.16 |
Django URLS, 루트를 앱에 매핑하는 방법은 무엇입니까? (0) | 2021.01.16 |