ASP.NET MVC 조건부 유효성 검사


129

데이터 주석을 사용하여 모델에서 조건부 유효성 검사를 수행하는 방법은 무엇입니까?

예를 들어 다음과 같은 모델 (개인 및 시니어)이 있다고 가정 해 보겠습니다.

public class Person
{
    [Required(ErrorMessage = "*")]
    public string Name
    {
        get;
        set;
    }

    public bool IsSenior
    {
        get;
        set;
    }

    public Senior Senior
    {
        get;
        set;
    }
}

public class Senior
{
    [Required(ErrorMessage = "*")]//this should be conditional validation, based on the "IsSenior" value
    public string Description
    {
        get;
        set;
    }
}

그리고 다음과 같은 견해 :

<%= Html.EditorFor(m => m.Name)%>
<%= Html.ValidationMessageFor(m => m.Name)%>

<%= Html.CheckBoxFor(m => m.IsSenior)%>
<%= Html.ValidationMessageFor(m => m.IsSenior)%>

<%= Html.CheckBoxFor(m => m.Senior.Description)%>
<%= Html.ValidationMessageFor(m => m.Senior.Description)%>

"IsSenior"속성 선택 (true-> 필수)에 따라 "Senior.Description"속성 조건부 필수 필드가되고 싶습니다. 데이터 주석을 사용하여 ASP.NET MVC 2에서 조건부 유효성 검사를 구현하는 방법은 무엇입니까?


1
나는 최근 비슷한 질문을했다 : stackoverflow.com/questions/2280539/…
Darin Dimitrov

혼란 스러워요. Senior객체는 항상 선배, 왜 IsSenior는이 경우에 거짓이 될 수 있습니다. Person.IsSeniorfalse 인 경우 'Person.Senior'속성이 null이 아니어야 합니다. 또는 IsSenior다음과 같이 속성을 구현하지 않는 것이 bool IsSenior { get { return this.Senior != null; } }좋습니다..
Steven

Steven : "IsSenior"는보기의 확인란 필드로 변환됩니다. 사용자가 "IsSenior"확인란을 선택하면 "Senior.Description"필드가 필수가됩니다.
Peter Stegnar

대린 디미트로프 (Dain Dimitrov) 오류 메시지가 특정 필드에 해당되는지 어떻게 알 수 있습니까? 객체 수준에서 유효성을 검사하면 객체 수준에서 오류가 발생합니다. 속성 수준에서 오류가 필요합니다.
Peter Stegnar

답변:


150

MVC3에 조건부 유효성 검사 규칙을 추가하는 훨씬 좋은 방법이 있습니다. 모델 IValidatableObjectValidate메소드를 상속 하고 구현하게하십시오 .

public class Person : IValidatableObject
{
    public string Name { get; set; }
    public bool IsSenior { get; set; }
    public Senior Senior { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
        if (IsSenior && string.IsNullOrEmpty(Senior.Description)) 
            yield return new ValidationResult("Description must be supplied.");
    }
}

ASP.NET MVC 3 소개 (미리보기 1) 에서 자세히 알아보십시오 .


property가 "int"유형 인 경우 값이 필요합니다. 해당 필드를 채우면 Validate가 작동하지 않습니다.
Jeyhun Rahimov

2
불행히도 Microsoft는 이것을 잘못된 계층에 넣었습니다. 유효성 검사는 비즈니스 논리이며이 인터페이스는 System.Web DLL에 있습니다. 이를 사용하려면 비즈니스 계층에 프레젠테이션 기술에 대한 종속성을 제공해야합니다.
NightOwl888

7
당신이 그것을 구현한다면 – falconwebtech.com/post/…
viperguynaz

4
falconwebtech.com/post/... -이 @viperguynaz 작동하지 않습니다
스 미트 파텔

1
당신이 호출해야 @RayLoveless ModelState.IsValid- 직접 유효성 검사를 호출하지
viperguynaz

63

컨트롤러에 포함 된 "ModelState" 사전 을 처리하여이 문제를 해결했습니다 . ModelState 사전에는 유효성을 검사해야하는 모든 멤버가 포함됩니다.

해결책은 다음과 같습니다.

속성 수준 오류 메시지를 유지하면서 일부 필드 (예 : A = true이면 B가 필요함)를 기반으로 조건부 유효성 검사 를 구현해야하는 경우 (객체 수준에있는 사용자 지정 유효성 검사기에는 해당되지 않음) "ModelState"를 처리하여 원치 않는 유효성 검사를 제거하면됩니다.

... 일부 수업에서 ...

public bool PropertyThatRequiredAnotherFieldToBeFilled
{
  get;
  set;
}

[Required(ErrorMessage = "*")] 
public string DepentedProperty
{
  get;
  set;
}

... 수업은 계속됩니다 ...

... 일부 컨트롤러 작업에서 ...

if (!PropertyThatRequiredAnotherFieldToBeFilled)
{
   this.ModelState.Remove("DepentedProperty");
}

...

이를 통해 조건부 유효성 검사를 수행하면서 다른 모든 항목은 동일하게 유지합니다.


최신 정보:

이것이 나의 최종 구현이다 : 나는 모델의 인터페이스와 상기 인터페이스를 구현하는 모델을 검증하는 action 속성을 사용했다. 인터페이스는 Validate (ModelStateDictionary modelState) 메소드를 규정합니다. action 속성은 IValidatorSomething에서 Validate (modelState)를 호출합니다.

이 답변을 복잡하게 만들고 싶지 않았으므로 최종 구현 세부 사항 (결국 생산 코드의 문제)에 대해서는 언급하지 않았습니다.


17
단점은 유효성 검사 논리 중 하나가 모델에 있고 다른 하나는 컨트롤러에 있다는 것입니다.
Kristof Claes

물론 이것은 필요하지 않습니다. 가장 기본적인 예를 보여줍니다. 모델의 인터페이스와 언급 된 인터페이스를 구현하는 모델의 유효성을 검사하는 작업 속성으로 이것을 구현했습니다. 인터페이스는 Validate (ModelStateDictionary modelState) 메소드를 사용합니다. 마지막으로 모델의 모든 유효성 검사를 수행하십시오. 어쨌든 좋은 지적입니다.
Peter Stegnar

MVC 팀이 더 나은 무언가를 구축 할 때까지는이 방법의 단순함이 마음에 듭니다. 그러나 솔루션이 클라이언트 측 유효성 검사를 사용하도록 작동합니까?
Aaron

2
@Aaron : 솔루션을 좋아하게되어 기쁘지만 불행히도이 솔루션은 모든 유효성 검사 속성에 JavaScript 구현이 필요하므로 클라이언트 측 유효성 검사와 함께 작동하지 않습니다. "Remote"속성을 사용하면 도움이 될 수 있으므로 Ajax 호출 만 발생하여 유효성을 검증합니다.
피터 스테 그나

이 답변을 확장 할 수 있습니까? 이것은 의미가 있지만, 나는 그것을 결정하고 싶습니다. 나는이 정확한 상황에 직면하고 있으며, 그것을 해결하고 싶습니다.
Richard B

36

어제 같은 문제가 있었지만 클라이언트 측과 서버 측 유효성 검사 모두에서 작동하는 매우 깨끗한 방식으로 문제를 해결했습니다.

조건 : 모델의 다른 속성 값을 기준으로 다른 속성을 필요로합니다. 여기 코드가 있습니다

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 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));

이것은 최초의 출발점이었습니다. miroprocessordev.blogspot.com/2012/08/…
Dan Hunex

asp.net mvc2에 동등한 솔루션이 있습니까? 에 ValidationResult, ValidationContext 클래스 asp.net MVC2에서 사용할 수없는 (.NET 프레임 워크 3.5)
User_MVC

2
이것은 링크 된 블로그 상태로 서버 측에서만 작동합니다
Pakman

2
MVC5를 사용하여 클라이언트 측 에서이 작업을 수행했지만 클라이언트에서는 DesiredValue가 무엇이든 유효성 검사를 시작합니다.
Geethanga

1
@ Dan Hunex : MVC4에서는 클라이언트 측에서 제대로 작동하지 않았으며 DesiredValue가 무엇이든 유효성 검사를 시작합니다. 어떤 도움 PLS?
Jack

34

나는 동적 주석의 수행이 놀라운 nuget 사용하고 ExpressiveAnnotations을

당신이 꿈꿀 수있는 논리를 검증 할 수 있습니다 :

public string Email { get; set; }
public string Phone { get; set; }
[RequiredIf("Email != null")]
[RequiredIf("Phone != null")]
[AssertThat("AgreeToContact == true")]
public bool? AgreeToContact { get; set; }

3
ExpressiveAnnotation 라이브러리는 여기에있는 모든 답변 중 가장 유연하고 일반적인 솔루션입니다. 공유해 주셔서 감사합니다!
Sudhanshu Mishra

2
나는 단단한 하루 동안 해결책을 찾으려고 머리를 두드리고 있었다. ExpressiveAnnotations가 나를위한 해결책 인 것 같습니다!
Caverman

ExpressiveAnnotation 라이브러리는 훌륭합니다!
Doug Knudsen

1
클라이언트 측도 지원합니다!
Nattrass

1
.NET Core는 지원하지 않으며 발생하지 않을 것 같습니다.
gosr

18

ModelState에서 오류를 제거하여 조건부 검사기를 조건부로 비활성화 할 수 있습니다.

ModelState["DependentProperty"].Errors.Clear();


6

이제 다른 편리한 데이터 주석 유효성 검사와 같은 조건부 유효성 검사를 수행하는 프레임 워크가 있습니다. http://foolproof.codeplex.com/

특히 [RequiredIfTrue ( "IsSenior")] 유효성 검사기를 살펴보십시오. 유효성을 검사하려는 속성에 직접 입력하면 "Senior"속성과 관련된 유효성 검사 오류의 원하는 동작이 나타납니다.

NuGet 패키지로 제공됩니다.


3

Senior 레벨이 아닌 Person 레벨에서 유효성을 검증해야합니다. Senior는 상위 Person에 대한 참조가 있어야합니다. 본인에게는 그 속성 중 하나가 아닌 개인에 대한 유효성 검사를 정의하는 자체 유효성 검사 메커니즘이 필요한 것 같습니다. 확실하지 않지만 DataAnnotations가 즉시 이것을 지원한다고 생각하지 않습니다. 당신이 할 수있는 AttributeValidationAttribute 그 클래스 수준에 장식과 다음도 그 클래스 수준의 검증을 실행할 수있는 사용자 정의 유효성 검사기를 생성 할 수 있습니다.

유효성 검사 응용 프로그램 블록은 기본적으로 자체 유효성 검사를 지원하지만 VAB에는 상당히 가파른 학습 곡선이 있습니다. 그럼에도 불구하고 다음은 VAB를 사용하는 예입니다.

[HasSelfValidation]
public class Person
{
    public string Name { get; set; }
    public bool IsSenior { get; set; }
    public Senior Senior { get; set; }

    [SelfValidation]
    public void ValidateRange(ValidationResults results)
    {
        if (this.IsSenior && this.Senior != null && 
            string.IsNullOrEmpty(this.Senior.Description))
        {
            results.AddResult(new ValidationResult(
                "A senior description is required", 
                this, "", "", null));
        }
    }
}

"시니어 레벨이 아닌 개인 레벨에서 유효성을 검증해야합니다."예, 이것은 옵션이지만, 시니어 오브젝트에 필요한 특정 필드에 오류가 추가되는 기능을 잃습니다.
Peter Stegnar

3

나는 같은 문제가 있었고, [필수] 속성의 수정이 필요했습니다-http 요청에 따라 필드를 작성하십시오. 솔루션은 Dan Hunex 답변과 비슷하지만 그의 솔루션은 올바르게 작동하지 않았습니다 (주석 참조). 나는 눈에 거슬리지 않는 유효성 검사를 사용하지 않고 MicrosoftMvcValidation.js를 즉시 사용합니다. 여기있어. 사용자 정의 속성을 구현하십시오.

public class RequiredIfAttribute : RequiredAttribute
{

    public RequiredIfAttribute(/*You can put here pararmeters if You need, as seen in other answers of this topic*/)
    {

    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {

    //You can put your logic here   

        return ValidationResult.Success;//I don't need its server-side so it always valid on server but you can do what you need
    }


}

그런 다음 전역에서 어댑터로 사용하려면 사용자 지정 공급자를 구현해야합니다.

public class RequreIfValidator : DataAnnotationsModelValidator <RequiredIfAttribute>
{

    ControllerContext ccontext;
    public RequreIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
       : base(metadata, context, attribute)
    {
        ccontext = context;// I need only http request
    }

//override it for custom client-side validation 
     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
     {       
               //here you can customize it as you want
         ModelClientValidationRule rule = new ModelClientValidationRule()
         {
             ErrorMessage = ErrorMessage,
    //and here is what i need on client side - if you want to make field required on client side just make ValidationType "required"    
             ValidationType =(ccontext.HttpContext.Request["extOperation"] == "2") ? "required" : "none";
         };
         return new ModelClientValidationRule[] { rule };
      }
}

그리고 global.asax를 한 줄로 수정하십시오.

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

그리고 여기에

[RequiredIf]
public string NomenclatureId { get; set; }

나를위한 주요 이점은 눈에 거슬리지 않는 유효성 검사의 경우처럼 사용자 정의 클라이언트 유효성 검사기를 코딩 할 필요가 없다는 것입니다. [필수]와 동일하게 작동하지만 원하는 경우에만 작동합니다.


확장 DataAnnotationsModelValidator에 대한 부분은 내가 볼 필요가 있었던 것입니다. 감사합니다.
twip


0

모델 상태에서 오류를 조건부로 제거하기위한 일반적인 사용법 :

  1. 컨트롤러 동작의 조건부 첫 부분 만들기
  2. ModelState에서 오류를 제거하는 논리 수행
  3. 기존 로직의 나머지 부분 (일반적으로 모델 상태 유효성 검사, 그 밖의 모든 작업)

예:

public ActionResult MyAction(MyViewModel vm)
{
    // perform conditional test
    // if true, then remove from ModelState (e.g. ModelState.Remove("MyKey")

    // Do typical model state validation, inside following if:
    //     if (!ModelState.IsValid)

    // Do rest of logic (e.g. fetching, saving

귀하의 예에서 모든 것을 그대로 유지하고 컨트롤러의 행동에 제안 된 논리를 추가하십시오. 컨트롤러 작업에 전달 된 ViewModel에 UI에서 데이터가 채워진 Person 및 Senior Person 개체가 있다고 가정합니다.


0

MVC 5를 사용하고 있지만 다음과 같이 시도 할 수 있습니다.

public DateTime JobStart { get; set; }

[AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")]
[DisplayName("Start Date")]
[Required]
public DateTime? StartDate { get; set; }

귀하의 경우 "IsSenior == true"와 같은 것을 말할 것입니다. 그런 다음 사후 작업에서 유효성 검사를 확인하면됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.