bestsource

IValidatableObject를 사용하는 방법은 무엇입니까?

bestsource 2023. 5. 4. 20:05
반응형

IValidatableObject를 사용하는 방법은 무엇입니까?

이해는 합니다.IValidatableObject속성을 서로 비교할 수 있는 방식으로 개체의 유효성을 검사하는 데 사용됩니다.

개별 속성의 유효성을 검사하는 속성을 계속 가지고 싶지만 특정 경우에는 일부 속성의 오류를 무시하고 싶습니다.

아래의 경우 제가 잘못 사용하려고 하는 건가요?그렇지 않다면 어떻게 구현해야 합니까?

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!this.Enable)
        {
            /* Return valid result here.
             * I don't care if Prop1 and Prop2 are out of range
             * if the whole object is not "enabled"
             */
        }
        else
        {
            /* Check if Prop1 and Prop2 meet their range requirements here
             * and return accordingly.
             */ 
        }
    }
}

먼저, 올바른 리소스를 알려주신 @paper1337님께 감사드립니다.제가 등록이 안 돼서 투표할 수가 없어요, 이걸 읽는 사람이 있다면 그렇게 해주세요.

여기 제가 하려고 했던 일을 성취하는 방법이 있습니다.

유효한 클래스:

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();
        if (this.Enable)
        {
            Validator.TryValidateProperty(this.Prop1,
                new ValidationContext(this, null, null) { MemberName = "Prop1" },
                results);
            Validator.TryValidateProperty(this.Prop2,
                new ValidationContext(this, null, null) { MemberName = "Prop2" },
                results);

            // some other random test
            if (this.Prop1 > this.Prop2)
            {
                results.Add(new ValidationResult("Prop1 must be larger than Prop2"));
            }
        }
        return results;
    }
}

사용.Validator.TryValidateProperty()유효성 검사에 실패한 경우 결과 컬렉션에 추가됩니다.검증에 실패하지 않은 경우 성공을 나타내는 결과 모음에 아무것도 추가되지 않습니다.

검증 수행:

    public void DoValidation()
    {
        var toValidate = new ValidateMe()
        {
            Enable = true,
            Prop1 = 1,
            Prop2 = 2
        };

        bool validateAllProperties = false;

        var results = new List<ValidationResult>();

        bool isValid = Validator.TryValidateObject(
            toValidate,
            new ValidationContext(toValidate, null, null),
            results,
            validateAllProperties);
    }

설정하는 것이 중요합니다.validateAllProperties이 방법이 작동하기 위해 거짓.언제validateAllPropertiesfalse only 속성은 다음과 같습니다.[Required]속성을 선택합니다.이를 통해IValidatableObject.Validate()메소드는 조건부 검증을 처리합니다.

Jeff Handley의 블로그 게시물에서 Validator를 사용한 검증 개체속성에 대한 인용:

개체를 검증할 때 Validator에서 다음 프로세스가 적용됩니다.검증 개체:

  1. 속성 수준 특성 검증
  2. 유효하지 않은 검증자가 있으면 유효성 검사를 중단하고 실패를 반환합니다.
  3. 개체 수준 특성 검증
  4. 유효하지 않은 검증자가 있으면 유효성 검사를 중단하고 실패를 반환합니다.
  5. 데스크톱 프레임워크에서 개체가 IValidatableObject를 구현하는 경우 Validate 메서드를 호출하고 오류를 반환합니다.

이는 #2 단계에서 유효성 검사가 중단되므로 수행하려는 작업이 즉시 실행되지 않음을 나타냅니다.기본 제공 속성에서 상속되는 속성을 만들고 인터페이스를 통해 활성화된 속성이 있는지 구체적으로 확인한 후 일반적인 유효성 검사를 수행할 수 있습니다.또는 엔티티를 검증하기 위한 모든 논리를 다음에 넣을 수 있습니다.Validate방법.

또한 의 정확한 구현을 확인할 수 있습니다.Validator여기 수업

몇 가지 요점만 추가하면 됩니다.

냐하면왜.Validate()가 반환합니다.IEnumerable<>결과를 천천히 생성하는 데 사용할 수 있습니다. 이는 검증 검사 중 일부가 IO 또는 CPU 집약적인 경우에 유용합니다.

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (this.Enable)
    {
        // ...
        if (this.Prop1 > this.Prop2)
        {
            yield return new ValidationResult("Prop1 must be larger than Prop2");
        }

이 또사용중경을 한다면,MVC ModelState 검사 를 유성검결실다패변로환수있할로 할 수 .ModelState다음과 같은 항목을 입력합니다(사용자 정의 모델 바인더에서 유효성 검사를 수행하는 경우 유용할 수 있습니다).

var resultsGroupedByMembers = validationResults
    .SelectMany(vr => vr.MemberNames
                        .Select(mn => new { MemberName = mn ?? "", 
                                            Error = vr.ErrorMessage }))
    .GroupBy(x => x.MemberName);

foreach (var member in resultsGroupedByMembers)
{
    ModelState.AddModelError(
        member.Key,
        string.Join(". ", member.Select(m => m.Error)));
}

검증을 위해 일반 사용 추상 클래스를 구현했습니다.

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

namespace App.Abstractions
{
    [Serializable]
    abstract public class AEntity
    {
        public int Id { get; set; }

        public IEnumerable<ValidationResult> Validate()
        {
            var vResults = new List<ValidationResult>();

            var vc = new ValidationContext(
                instance: this,
                serviceProvider: null,
                items: null);

            var isValid = Validator.TryValidateObject(
                instance: vc.ObjectInstance,
                validationContext: vc,
                validationResults: vResults,
                validateAllProperties: true);

            /*
            if (true)
            {
                yield return new ValidationResult("Custom Validation","A Property Name string (optional)");
            }
            */

            if (!isValid)
            {
                foreach (var validationResult in vResults)
                {
                    yield return validationResult;
                }
            }

            yield break;
        }


    }
}

허용된 응답의 문제는 개체의 유효성을 제대로 검사하기 위해 호출자에게 의존한다는 것입니다.RangeAttribute를 제거하고 Validate 메서드 내에서 범위 유효성 검사를 수행하거나 생성자에서 필수 속성의 이름을 인수로 사용하는 사용자 지정 특성 하위 분류를 만듭니다.

예:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class RangeIfTrueAttribute : RangeAttribute
{
    private readonly string _NameOfBoolProp;

    public RangeIfTrueAttribute(string nameOfBoolProp, int min, int max) : base(min, max)
    {
        _NameOfBoolProp = nameOfBoolProp;
    }

    public RangeIfTrueAttribute(string nameOfBoolProp, double min, double max) : base(min, max)
    {
        _NameOfBoolProp = nameOfBoolProp;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(_NameOfBoolProp);
        if (property == null)
            return new ValidationResult($"{_NameOfBoolProp} not found");

        var boolVal = property.GetValue(validationContext.ObjectInstance, null);

        if (boolVal == null || boolVal.GetType() != typeof(bool))
            return new ValidationResult($"{_NameOfBoolProp} not boolean");

        if ((bool)boolVal)
        {
            return base.IsValid(value, validationContext);
        }
        return null;
    }
}

시스템을 사용하는 것보다 IV ValidatableObject 또는 속성 수준 검증(속성)을 사용하여 검증 로직을 구현합니다.구성요소 모델.데이터 주석.이와 같은 검증자 클래스

var validationContext = new ValidationContext(model,, null, null);
var validations = new Collection<ValidationResult>();
Validator.TryValidaObject(model, validationContext, validations, true)

유효성 검사 컬렉션에 오류가 있어야 합니다(ErrorMessage 속성은 비워둘 수 없습니다).

https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validator?view=net-6.0

저는 그 콜 베이스를 제외하고 코코자의 대답이 좋았습니다.IsValid는 IsValid 메서드를 다시 입력할 때 스택 오버플로 예외를 발생시킵니다.그래서 저는 특정 유형의 검증을 위해 수정했습니다. 제 경우에는 이메일 주소를 위한 것이었습니다.

[AttributeUsage(AttributeTargets.Property)]
class ValidEmailAddressIfTrueAttribute : ValidationAttribute
{
    private readonly string _nameOfBoolProp;

    public ValidEmailAddressIfTrueAttribute(string nameOfBoolProp)
    {
        _nameOfBoolProp = nameOfBoolProp;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (validationContext == null)
        {
            return null;
        }

        var property = validationContext.ObjectType.GetProperty(_nameOfBoolProp);
        if (property == null)
        {
            return new ValidationResult($"{_nameOfBoolProp} not found");
        }

        var boolVal = property.GetValue(validationContext.ObjectInstance, null);

        if (boolVal == null || boolVal.GetType() != typeof(bool))
        {
            return new ValidationResult($"{_nameOfBoolProp} not boolean");
        }

        if ((bool)boolVal)
        {
            var attribute = new EmailAddressAttribute {ErrorMessage = $"{value} is not a valid e-mail address."};
            return attribute.GetValidationResult(value, validationContext);
        }
        return null;
    }
}

이것이 훨씬 더 잘 작동합니다!충돌하지 않고 좋은 오류 메시지가 나타납니다.이것이 누군가에게 도움이 되기를 바랍니다!

iValidate에 대해 마음에 들지 않는 점은 다른 모든 검증 후에만 실행되는 것처럼 보인다는 것입니다.
또한 적어도 우리 사이트에서는 저장 시도 중에 다시 실행됩니다.함수를 만들고 모든 유효성 검사 코드를 입력하는 것이 좋습니다.또는 웹 사이트의 경우 모델이 생성된 후 컨트롤러에서 "특수" 유효성 검사를 받을 수 있습니다. 예:

 public ActionResult Update([DataSourceRequest] DataSourceRequest request, [Bind(Exclude = "Terminal")] Driver driver)
    {

        if (db.Drivers.Where(m => m.IDNumber == driver.IDNumber && m.ID != driver.ID).Any())
        {
            ModelState.AddModelError("Update", string.Format("ID # '{0}' is already in use", driver.IDNumber));
        }
        if (db.Drivers.Where(d => d.CarrierID == driver.CarrierID
                                && d.FirstName.Equals(driver.FirstName, StringComparison.CurrentCultureIgnoreCase)
                                && d.LastName.Equals(driver.LastName, StringComparison.CurrentCultureIgnoreCase)
                                && (driver.ID == 0 || d.ID != driver.ID)).Any())
        {
            ModelState.AddModelError("Update", "Driver already exists for this carrier");
        }

        if (ModelState.IsValid)
        {
            try
            {

언급URL : https://stackoverflow.com/questions/3400542/how-do-i-use-ivalidatableobject

반응형