ASP.NET Core MVC 및 Razor Pages의 모델 유효성 검사

이 문서에서는 ASP.NET Core MVC 또는 Razor Pages 앱에서 사용자 입력의 유효성을 검사하는 방법에 대해 설명합니다.

예제 코드 살펴보기 및 다운로드 (다운로드 방법). 다운로드 예제는 영역을 테스트하기 위한 기초적인 앱을 제공합니다.

모델 상태

모델 상태는 모델 바인딩 및 모델 유효성 검사 두 하위 시스템에서 발생하는 오류를 나타냅니다. 모델 바인딩에서 발생하는 오류는 일반적으로 데이터 변환 오류입니다. 예를 들어 정수 필드에 “x”가 입력됩니다. 모델 유효성 검사는 모델 바인딩 후에 발생하며 데이터가 비즈니스 규칙에 맞지 않으면 오류를 보고합니다. 예를 들어 1에서 5 사이의 등급을 필요한 필드에 0이 입력됩니다.

모델 바인딩과 모델 유효성 검사 모두 컨트롤러 작업 또는 Razor Pages 처리기 메서드를 실행하기 전에 실행됩니다. 웹앱의 경우 ModelState.IsValid를 검사하고 적절히 반응하는 기능은 앱에서 실행합니다. 웹앱은 일반적으로 다음 Razor 페이지 예제와 같이 오류 메시지로 페이지를 다시 표시합니다.

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

컨트롤러 및 뷰가 있는 ASP.NET Core MVC의 경우 다음 예제에서는 컨트롤러 작업 내부를 확인하는 ModelState.IsValid 방법을 보여 줍니다.

public async Task<IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }

    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
}

Web API 컨트롤러는 [ApiController] 특성이 있는지 확인할 ModelState.IsValid 필요가 없습니다. 이 경우 모델 상태가 잘못되면 오류 세부 정보를 포함하는 자동 HTTP 400 응답이 반환됩니다. 자세한 정보는 자동 HTTP 400 응답을 참조하세요.

유효성 검사 다시 실행

유효성 검사는 자동으로 실행 되지만 수동으로 반복하는 것이 좋습니다. 예를 들어 속성에 대한 값을 계산하고 해당 속성을 계산된 값으로 설정한 후 유효성 검사를 다시 실행하는 것이 좋습니다. 유효성 검사를 다시 실행하려면 ModelStateDictionary.ClearValidationState를 호출하여 TryValidateModel에 따라 유효성이 검사되는 모델에 대한 특정 유효성 검사를 제거합니다.

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

유효성 검사 특성

유효성 검사 특성을 사용하여 모델 속성에 대한 유효성 검사 규칙을 지정할 수 있습니다. 샘플 앱의 다음 예제에서는 유효성 검사 특성으로 주석이 추가된 모델 클래스를 보여줍니다. 특성은 [ClassicMovie] 사용자 지정 유효성 검사 특성이며 다른 특성은 기본 제공됩니다. 사용자 지정 특성을 구현하는 다른 방법을 보여 주는 [ClassicMovieWithClientValidator]는 표시되지 않습니다.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

기본 제공 특성

다음은 몇 가지 기본 제공 유효성 검사 특성입니다.

  • [ValidateNever]: 속성 또는 매개 변수를 유효성 검사에서 제외해야 임을 나타냅니다.
  • [신용 카드]: 속성에 신용 카드 형식이 있는지 확인합니다. jQuery 유효성 검사 추가 방법이 필요합니다.
  • [비교]: 모델의 두 속성이 일치하는지 확인합니다.
  • [EmailAddress]: 속성에 전자 메일 형식이 있는지 확인합니다.
  • [전화]: 속성에 전화 번호 형식이 지정되었는지 확인합니다.
  • [Range]: 속성 값이 지정된 범위 내에 속하는지 확인합니다.
  • [RegularExpression]: 속성 값이 지정된 정규식과 일치하는지 확인합니다.
  • [필수]: 필드가 null이 아닌지 확인합니다. 이 특성의 동작에 대한 자세한 내용은 [Required] 특성을 참조하세요.
  • [StringLength]: 문자열 속성 값이 지정된 길이 제한을 초과하지 않는지 확인합니다.
  • [URL]: 속성에 URL 형식이 있는지 확인합니다.
  • [원격]: 서버에서 작업 메서드를 호출하여 클라이언트에서 입력의 유효성을 검사합니다. 이 특성의 동작에 대한 자세한 내용은 [Remote] 특성을 참조하세요.

네임스페이스에서 System.ComponentModel.DataAnnotations 유효성 검사 특성의 전체 목록을 찾을 수 있습니다.

오류 메시지

유효성 검사 특성을 사용하여 잘못된 입력에 대해 표시할 오류 메시지를 지정할 수 있습니다. 예를 들어:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

내부적으로 이 특성은 필드 이름에 대한 자리 표시자 및 경우에 따라 추가 자리 표시자를 사용하여 String.Format을 호출합니다. 예를 들어:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Name 속성에 적용할 경우 위의 코드에 의해 생성되는 오류 메시지는 "이름의 길이는 6문자에서 8문자 사이여야 합니다"일 것입니다.

특정 특성의 오류 메시지에 대해 String.Format 에 전달되는 매개 변수를 알아보려면 DataAnnotations 소스 코드를 참조하세요.

nullable이 아닌 참조 형식 및 [필수] 특성

유효성 검사 시스템은 Null을 허용하지 않는 매개 변수 또는 바인딩되는 속성을 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리합니다. 컨텍스트를 Nullable 사용하도록 설정하면 MVC는 제네릭이 아닌 형식 또는 매개 변수가 특성으로 특성화된 것처럼 nullable이 아닌 속성의 [Required(AllowEmptyStrings = true)] 유효성을 암시적으로 검사하기 시작합니다. 다음 코드를 살펴보세요.

public class Person
{
    public string Name { get; set; }
}

앱이 빌드<Nullable>enable</Nullable>된 경우 ON 또는 양식 게시에 JS대한 Name 값이 누락되면 유효성 검사 오류가 발생합니다. Null 허용 참조 형식을 사용하여 Name 속성에 null 또는 누락된 값을 지정할 수 있습니다.

public class Person
{
    public string? Name { get; set; }
}

Program.cs에서 SuppressImplicitRequiredAttributeForNonNullableReferenceTypes를 구성하여 이 동작을 사용하지 않도록 설정할 수 있습니다.

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

제네릭 형식 및 [필수] 특성의 nullable이 아닌 속성

제네릭 형식의 nullable이 아닌 속성은 형식이 [Required] 필요한 경우 특성을 포함해야 합니다. 다음 코드에서는 TestRequired 필요하지 않습니다.

public class WeatherForecast<T>
{
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

다음 코드 TestRequired 에서는 명시적으로 필수로 표시됩니다.

using System.ComponentModel.DataAnnotations;

public class WeatherForecast<T>
{
    [Required]
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

서버에 대한 [Required] 유효성 검사

서버에서 속성이 Null인 경우 필수 값이 없는 것으로 간주합니다. Null을 허용하지 않는 필드는 언제나 유효하며 [Required] 특성의 오류 메시지는 표시되지 않습니다.

그러나 Null을 허용하지 않는 속성에 대한 모델 바인딩이 실패하여 The value '' is invalid와 같은 오류 메시지가 표시될 수 있습니다. Null을 허용하지 않는 형식의 서버 쪽 유효성 검사에 대한 사용자 지정 오류 메시지를 지정하려는 경우 다음과 같은 방법이 있습니다.

  • 필드를 Null 허용으로 만듭니다(예: decimal 대신에 decimal?). Nullable< T> 값 형식은 표준 nullable 형식처럼 처리됩니다.

  • 다음 예제에서와 같이 모델 바인딩에 의해 사용할 기본 오류 메시지를 지정합니다.

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

    기본 메시지를 설정할 수 있는 모델 바인딩 오류에 대한 자세한 내용은 DefaultModelBindingMessageProvider를 참조하십시오.

클라이언트에 대한 [Required] 유효성 검사

클라이언트에서 Null을 허용하지 않는 형식 및 문자열은 서버의 경우와 다르게 처리됩니다. 클라이언트에서:

  • 값은 해당 값에 대한 입력이 있는 경우에만 존재하는 것으로 간주됩니다. 그러므로 클라이언트 쪽 유효성 검사에서는 Null을 허용하지 않는 형식을 Null 허용 형식과 동일하게 처리합니다.
  • 문자열 필드의 공백은 jQuery 유효성 검사 필수 메서드에 의해 유효한 입력으로 간주됩니다. 서버 쪽 유효성 검사에서는 공백만 입력된 경우 필수 문자열 필드를 잘못된 것으로 간주합니다.

위에서 설명했듯이 Null을 허용하지 않는 형식은 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리됩니다. 즉, [Required(AllowEmptyStrings = true)] 특성을 적용하지 않더라도 클라이언트 쪽 유효성 검사가 이루어집니다. 그러나 해당 특성을 사용하지 않으면 기본 오류 메시지가 표시됩니다. 사용자 지정 오류 메시지를 지정하려면 해당 특성을 사용하십시오.

[Remote] 특성

[원격] 특성은 필드 입력이 유효한지 여부를 확인하기 위해 서버에서 메서드를 호출해야 하는 클라이언트 쪽 유효성 검사를 구현합니다. 예를 들어 앱에서 사용자 이름을 이미 사용 중인지 여부를 확인해야 할 수 있습니다.

원격 유효성 검사를 구현하려면:

  1. JavaScript가 호출할 작업 메서드를 만듭니다. jQuery 유효성 검사 원격 메서드에는 ON 응답이 JS예상됩니다.

    • true는 입력 데이터가 유효함을 의미합니다.
    • false, undefined 또는 null은 입력이 잘못되었음을 의미합니다. 기본 오류 메시지를 표시합니다.
    • 다른 문자열은 모두 입력이 잘못되었음을 의미합니다. 문자열을 사용자 지정 오류 메시지로 표시합니다.

    다음은 사용자 지정 오류 메시지를 반환하는 작업 메서드의 예입니다.

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. 다음 예제와 같이 모델 클래스에서는 유효성 검사 작업 메서드를 가리키는 [Remote] 특성으로 속성에 주석을 답니다.

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; } = null!;
    

추가 필드

[Remote] 특성의 AdditionalFields 속성을 사용하여 서버의 데이터를 기준으로 필드 조합의 유효성을 검사할 수 있습니다. 예를 들어 User 모델이 FirstNameLastName 속성을 포함한 경우 해당 이름 쌍을 이미 가진 기존 사용자가 없는지 확인하는 것이 좋습니다. 다음 예제에서는 AdditionalFields을 사용하는 방법을 보여 줍니다.

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;

AdditionalFields는 명시적으로 믄자열 "FirstName" 및 "LastName"으로 설정할 수 있지만 nameof 연산자를 사용하면 나중에 리팩터링이 간단해집니다. 이 유효성 검사의 작업 메서드는 firstNamelastName 인수를 모두 허용해야 합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

사용자가 이름 또는 성을 입력하면 JavaScript에서는 원격 호출을 실행하여 해당 이름 쌍이 사용 중인지 확인합니다.

두 개 이상의 추가 필드에 대한 유효성을 검사하려면 해당 필드를 쉼표로 구분된 목록으로 제공합니다. 예를 들어 MiddleName 속성을 모델에 추가하려면 [Remote] 특성을 다음 예제와 같이 설정합니다.

[Remote(action: "VerifyName", controller: "Users",
    AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

모든 특성 인수와 같은 AdditionalFields은 상수 식이어야 합니다. 따라서 AdditionalFields를 초기화하기 위해 보간된 문자열을 사용하거나 Join을 호출하지 마십시오.

기본 제공 특성에 대한 대안

기본 제공 특성이 제공하지 않는 유효성 검사가 필요한 경우 다음과 같이 할 수 있습니다.

사용자 지정 특성

기본 제공 유효성 검사 특성이 처리하지 않는 시나리오의 경우 사용자 지정 유효성 검사 특성을 만들 수 있습니다. ValidationAttribute에서 상속하는 클래스를 만들고 IsValid 메서드를 재정의합니다.

IsValid 메서드에 대해서는 유효성을 검사할 입력인 이라는 개체를 지정할 수 있습니다. 또한 오버로드에 대해서는 모델 바인딩에 의해 생성된 모델 인스턴스와 같은 추가 정보를 제공하는 ValidationContext 개체를 지정할 수 있습니다.

다음 예제에서는 클래식 장르의 영화에 대한 개봉 날짜가 지정된 연도보다 이후가 아닌지 유효성을 검사합니다. [ClassicMovie] 특성:

  • 서버에서만 실행됩니다.
  • 클래식 동영상의 경우 릴리스 날짜의 유효성을 검사합니다.
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

위의 예제에서 movie 변수는 양식 제출에서 제공된 데이터를 포함하는 Movie 개체를 나타냅니다. 유효성 검사에 실패하면 오류 메시지가 발생하여 ValidationResult가 반환됩니다.

IValidatableObject

앞의 예제는 Movie 형식에 대해서만 작동합니다. 또 다른 클래스 수준 유효성 검사 방법은 다음 예제와 같이 모델 클래스 내에 IValidatableObject를 구현하는 것입니다.

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

최상위 노드 유효성 검사

최상위 수준 노드에는 다음이 포함됩니다.

  • 작업 매개 변수
  • 컨트롤러 속성
  • 페이지 처리기 매개 변수
  • 페이지 모델 속성

모델 바인딩 최상위 노드는 모델 속성의 유효성을 검사하는 것 외에도 유효성이 검사됩니다. 샘플 앱의 다음 예제에서 메서드는 VerifyPhone 작업 매개 변수의 RegularExpressionAttribute 유효성을 phone 검사하는 데 사용합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

최상위 노드는 유효성 검사 특성과 함께 BindRequiredAttribute를 사용할 수 있습니다. 샘플 앱CheckAge의 다음 예제에서 메서드는 양식이 age 제출될 때 매개 변수를 쿼리 문자열에서 바인딩해야 한다고 지정합니다.

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Check Age 페이지(CheckAge.cshtml)에는 두 가지 양식이 있습니다. 첫 번째 양식은 99Age 값을 쿼리 문자열 매개 변수(https://localhost:5001/Users/CheckAge?Age=99)로 제출합니다.

쿼리 문자열에서 올바른 서식이 지정된 age 매개 변수를 제출하면 양식이 유효성을 검사합니다.

기간 확인 페이지의 두 번째 양식은 요청 본문의 Age 값을 제출하고 유효성 검사가 실패합니다. age 매개 변수는 쿼리 문자열에서 가져와야 하므로 바인딩이 실패합니다.

최대 오류 수

유효성 검사는 최대 오류 수(기본값 200)에 도달하면 중지됩니다. Program.cs에 다음 코드로 이 번호를 구성할 수 있습니다.

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

builder.Services.AddSingleton
    <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

최대 재귀

ValidationVisitor는 유효성 검사 중인 모델의 개체 그래프를 트래버스합니다. 깊거나 무한히 재귀하는 모델의 경우 유효성 검사를 실행하면 스택 오버플로가 발생할 수 있습니다. MvcOptions.MaxValidationDepth 는 방문자 재귀가 구성된 깊이를 초과하는 경우 유효성 검사를 일찍 중지하는 방법을 제공합니다. MvcOptions.MaxValidationDepth의 기본값은 32입니다.

자동 단락

모델 그래프에 대한 유효성 검사가 필요하지 않은 경우 유효성 검사는 자동으로 단락됩니다(건너뜀). 런타임에 유효성 검사를 건너뛰는 개체로는 기본 형식(byte[], string[], Dictionary<string, string>) 수집 및 유효성 검사기를 포함하지 않은 복합 개체 그래프가 있습니다.

클라이언트 쪽 유효성 검사

클라이언트 쪽 유효성 검사는 형식이 유효할 때까지 전송을 방지합니다. 제출 단추는 형식을 전송하거나 오류 메시지를 표시하는 JavaScript를 실행합니다.

클라이언트 쪽 유효성 검사는 양식에 대한 입력 오류가 있는 경우 불필요한 서버 왕복을 방지합니다. 다음 스크립트는 클라이언트 쪽 유효성 검사를 참조 _Layout.cshtml 하고 _ValidationScriptsPartial.cshtml 지원합니다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>

jQuery 비간섭 유효성 검사 스크립트는 널리 사용되는 jQuery 유효성 검사 플러그 인에 기반한 사용자 지정 Microsoft 프런트 엔드 라이브러리입니다. jQuery 비간섭 유효성 검사를 사용하지 않을 경우 두 위치(모델 속성에 대한 서버 쪽 유효성 검사 특성에서 한 번 및 클라이언트 쪽 스크립트에서 다시 한 번)에서 동일한 유효성 검사 논리를 코딩해야 할 수 있습니다. 그 대신 태그 도우미HTML 도우미 는 유효성 검사가 필요한 양식 요소에 대해 모델 특성의 유효성 검사 특성 및 형식 메타데이터를 사용하여 HTML 5 data- 특성을 렌더링합니다. jQuery 비간섭 유효성 검사는 data- 특성을 구문 분석하고 jQuery 유효성 검사로 논리를 전달하여 효과적으로 서버 쪽 유효성 검사 논리를 클라이언트에 “복사”합니다. 다음과 같이 태그 도우미를 사용하여 클라이언트에서 유효성 검사 오류를 표시할 수 있습니다.

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

위의 태그 도우미는 다음 HTML을 렌더링합니다.

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

HTML의 data- 특성 출력은 Movie.ReleaseDate 속성에 대한 유효성 검사 특성에 해당합니다. data-val-required 특성은 사용자가 릴리스 날짜 필드를 입력하지 않았음을 표시하는 오류 메시지를 포함합니다. jQuery 눈에 거슬리지 않는 유효성 검사는 이 값을 jQuery Validation required() 메서드에 전달한 다음, 해당 메시지를 함께 <제공되는 범위> 요소에 표시합니다.

데이터 형식 유효성 검사는 [DataType] 특성으로 재정의되지 않는 한 속성의 .NET 형식을 기반으로 합니다. 브라우저는 고유한 기본 오류 메시지를 가지고 있지만 jQuery유효성 검사의 비간섭 유효성 검사 패키지는 해당 메시지를 재정의할 수 있습니다. [DataType] 특성 및 하위 클래스(예: [EmailAddress]) 를 사용하면 오류 메시지를 지정할 수 있습니다.

비간섭 유효성 검사

비간섭 유효성 검사에 대한 자세한 내용은 이 GitHub 문제를 참조하세요.

동적 형식에 유효성 검사 추가

jQuery 비간섭 유효성 검사는 페이지가 먼저 로드되는 경우 유효성 검사 논리 및 매개 변수를 jQuery 유효성 검사에 전달합니다. 따라서 동적으로 생성된 양식에 대해서는 유효성 검사가 자동으로 작동하지 않습니다. 유효성 검사를 사용하도록 설정하려면 jQuery 비간섭 유효성 검사에서 동적 폼을 만든 후에 즉시 구문 분석하도록 지시합니다. 예를 들어 다음 코드에서는 AJAX를 통해 추가된 양식에 대해 클라이언트 쪽 유효성 검사를 설정합니다.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

$.validator.unobtrusive.parse() 메서드는 하나의 인수에 대해 jQuery 선택기를 허용합니다. 이 메서드는 jQuery 비간섭 유효성 검사에서 해당 선택기 내에 있는 형식의 data- 특성을 구문 분석하도록 지시합니다. 그러면 이러한 특성 값이 jQuery 유효성 검사 플러그 인에 전달됩니다.

동적 컨트롤에 유효성 검사 추가

$.validator.unobtrusive.parse() 메서드는 <input><select/>와 같은 동적으로 생성된 개별 컨트롤이 아닌 전체 양식에 대해 작용합니다. 양식을 다시 구문 분석하려면 다음 예제와 같이 이전에 양식을 구문 분석했을 때 추가된 유효성 검사 데이터를 제거합니다.

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

사용자 지정 클라이언트 쪽 유효성 검사

사용자 지정 클라이언트 쪽 유효성 검사는 사용자 지정 jQuery 유효성 검사 어댑터에서 작동하는 data- HTML 특성을 생성하여 수행됩니다. 다음 샘플 어댑터 코드는 이 문서에서 이전에 소개한 [ClassicMovie][ClassicMovieWithClientValidator] 특성용으로 작성되었습니다.

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

어댑터 작성 방법에 대한 자세한 내용은 jQuery 유효성 검사 설명서를 참조하세요.

지정된 필드에 대한 어댑터 사용은 data- 특성에 의해 트리거됩니다.

  • 필드를 유효성 검사가 적용되는 것으로 표시합니다(data-val="true").
  • 유효성 검사 규칙 이름 및 오류 메시지 텍스트(예: data-val-rulename="Error message.")를 식별합니다.
  • 유효섬 검사기에 필요한 추가 매개 변수(예: data-val-rulename-param1="value")를 제공합니다.

다음 예제에서는 샘플 앱의ClassicMovie 특성에 대한 특성을 보여줍니다data-.

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

앞에서 설명했듯이 태그 도우미HTML 도우미는 유효성 검사 특성의 정보를 사용하여 data- 특성을 렌더링합니다. 사용자 지정 data- HTML 특성을 생성하는 코드를 작성하는 두 가지 방법이 있습니다.

  • AttributeAdapterBase<TAttribute>에서 파생하는 클래스 및 IValidationAttributeAdapterProvider를 구현하는 클래스를 만들고 사용자의 특성 및 해당 어댑터를 DI에 등록합니다. 이 메서드는 서버 관련 및 클라이언트 관련 유효성 검사 코드가 별도의 클래스에 있는 단일 책임 원칙 을 따릅니다. 또한 어댑터는 DI에 등록되어 있으므로 필요한 경우 DI의 다른 서비스를 사용할 수 있다는 장점이 있습니다.
  • 사용자의 ValidationAttribute 클래스에서 IClientModelValidator를 구현합니다. 이 방법은 특성이 서버 쪽 유효성 검사를 수행하지 않고 DI의 서비스가 필요하지 않은 경우 적절할 수 있습니다.

클라이언트 쪽 유효성 검사에 대한 특성 어댑터

HTML에서 특성을 렌더링하는 data- 이 방법은 샘플 앱ClassicMovie 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  1. 사용자 지정 유효성 검사 특성에 대한 특성 어댑터 클래스를 생성합니다. AttributeAdapterBase<TAttribute>에서 클래스를 파생합니다. 이 예제와 같이 렌더링된 출력에 data- 특성을 추가하는 AddValidation 메서드를 생성합니다.

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(
            ClassicMovieAttribute attribute, IStringLocalizer? stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
            => Attribute.GetErrorMessage();
    }
    
  2. IValidationAttributeAdapterProvider를 구현하는 어댑터 공급자 클래스를 생성합니다. GetAttributeAdapter 메서드에서 다음 예제와 같이 사용자 지정 특성을 어댑터의 생성자에 전달합니다.

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter? GetAttributeAdapter(
            ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. DI용 어댑터 공급자를 Program.cs에 등록합니다.

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

클라이언트 쪽 유효성 검사를 위한 IClientModelValidator

HTML에서 특성을 렌더링하는 data- 이 방법은 샘플 앱ClassicMovieWithClientValidator 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  • 사용자 지정 유효성 검사 특성에서 IClientModelValidator 인터페이스를 구현하고 AddValidation 메서드를 생성합니다. AddValidation 메서드에서 다음 예제와 같이 유효성 검사를 위한 data- 특성을 추가합니다.

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
            => Year = year;
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult? IsValid(
            object? value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value!).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정

다음 코드는 Razor Pages에서 클라이언트 유효성 검사를 사용하지 않도록 설정합니다.

builder.Services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정하는 다른 옵션:

  • 모든 파일에 대한 참조를 _ValidationScriptsPartial 주석으로 처리합니다 .cshtml .
  • Pages\Shared_ValidationScriptsPartial.cshtml 파일의 내용을 제거합니다.

앞의 접근 방식은 ASP.NET Core IdentityRazor 클래스 라이브러리의 클라이언트 쪽 유효성 검사를 방지하지 않습니다. 자세한 내용은 ASP.NET Core 프로젝트에서 Identity 스캐폴드를 참조하세요.

추가 리소스

이 문서에서는 ASP.NET Core MVC 또는 Razor Pages 앱에서 사용자 입력의 유효성을 검사하는 방법에 대해 설명합니다.

예제 코드 살펴보기 및 다운로드 (다운로드 방법). 다운로드 예제는 영역을 테스트하기 위한 기초적인 앱을 제공합니다.

모델 상태

모델 상태는 모델 바인딩 및 모델 유효성 검사 두 하위 시스템에서 발생하는 오류를 나타냅니다. 모델 바인딩에서 발생하는 오류는 일반적으로 데이터 변환 오류입니다. 예를 들어 정수 필드에 “x”가 입력됩니다. 모델 유효성 검사는 모델 바인딩 후에 발생하며 데이터가 비즈니스 규칙에 맞지 않으면 오류를 보고합니다. 예를 들어 1에서 5 사이의 등급을 필요한 필드에 0이 입력됩니다.

모델 바인딩과 모델 유효성 검사 모두 컨트롤러 작업 또는 Razor Pages 처리기 메서드를 실행하기 전에 실행됩니다. 웹앱의 경우 ModelState.IsValid를 검사하고 적절히 반응하는 기능은 앱에서 실행합니다. 웹앱은 일반적으로 다음 Razor 페이지 예제와 같이 오류 메시지로 페이지를 다시 표시합니다.

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

컨트롤러 및 뷰가 있는 ASP.NET Core MVC의 경우 다음 예제에서는 컨트롤러 작업 내부를 확인하는 ModelState.IsValid 방법을 보여 줍니다.

public async Task<IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }

    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
}

Web API 컨트롤러는 [ApiController] 특성이 있는지 확인할 ModelState.IsValid 필요가 없습니다. 이 경우 모델 상태가 잘못되면 오류 세부 정보를 포함하는 자동 HTTP 400 응답이 반환됩니다. 자세한 정보는 자동 HTTP 400 응답을 참조하세요.

유효성 검사 다시 실행

유효성 검사는 자동으로 실행 되지만 수동으로 반복하는 것이 좋습니다. 예를 들어 속성에 대한 값을 계산하고 해당 속성을 계산된 값으로 설정한 후 유효성 검사를 다시 실행하는 것이 좋습니다. 유효성 검사를 다시 실행하려면 ModelStateDictionary.ClearValidationState를 호출하여 TryValidateModel에 따라 유효성이 검사되는 모델에 대한 특정 유효성 검사를 제거합니다.

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

유효성 검사 특성

유효성 검사 특성을 사용하여 모델 속성에 대한 유효성 검사 규칙을 지정할 수 있습니다. 샘플 앱의 다음 예제에서는 유효성 검사 특성으로 주석이 추가된 모델 클래스를 보여줍니다. 특성은 [ClassicMovie] 사용자 지정 유효성 검사 특성이며 다른 특성은 기본 제공됩니다. 사용자 지정 특성을 구현하는 다른 방법을 보여 주는 [ClassicMovieWithClientValidator]는 표시되지 않습니다.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

기본 제공 특성

다음은 몇 가지 기본 제공 유효성 검사 특성입니다.

  • [ValidateNever]: 속성 또는 매개 변수를 유효성 검사에서 제외해야 임을 나타냅니다.
  • [신용 카드]: 속성에 신용 카드 형식이 있는지 확인합니다. jQuery 유효성 검사 추가 방법이 필요합니다.
  • [비교]: 모델의 두 속성이 일치하는지 확인합니다.
  • [EmailAddress]: 속성에 전자 메일 형식이 있는지 확인합니다.
  • [전화]: 속성에 전화 번호 형식이 지정되었는지 확인합니다.
  • [Range]: 속성 값이 지정된 범위 내에 속하는지 확인합니다.
  • [RegularExpression]: 속성 값이 지정된 정규식과 일치하는지 확인합니다.
  • [필수]: 필드가 null이 아닌지 확인합니다. 이 특성의 동작에 대한 자세한 내용은 [Required] 특성을 참조하세요.
  • [StringLength]: 문자열 속성 값이 지정된 길이 제한을 초과하지 않는지 확인합니다.
  • [URL]: 속성에 URL 형식이 있는지 확인합니다.
  • [원격]: 서버에서 작업 메서드를 호출하여 클라이언트에서 입력의 유효성을 검사합니다. 이 특성의 동작에 대한 자세한 내용은 [Remote] 특성을 참조하세요.

네임스페이스에서 System.ComponentModel.DataAnnotations 유효성 검사 특성의 전체 목록을 찾을 수 있습니다.

오류 메시지

유효성 검사 특성을 사용하여 잘못된 입력에 대해 표시할 오류 메시지를 지정할 수 있습니다. 예를 들어:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

내부적으로 이 특성은 필드 이름에 대한 자리 표시자 및 경우에 따라 추가 자리 표시자를 사용하여 String.Format을 호출합니다. 예를 들어:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Name 속성에 적용할 경우 위의 코드에 의해 생성되는 오류 메시지는 "이름의 길이는 6문자에서 8문자 사이여야 합니다"일 것입니다.

특정 특성의 오류 메시지에 대해 String.Format 에 전달되는 매개 변수를 알아보려면 DataAnnotations 소스 코드를 참조하세요.

유효성 검사 오류에 ON 속성 이름 사용 JS

기본적으로 유효성 검사 오류가 발생하면 모델 유효성 검사는 속성 이름을 오류 키로 사용하여 생성합니다 ModelStateDictionary . 단일 페이지 앱과 같은 일부 앱은 Web API에서 생성된 유효성 검사 오류에 ON 속성 이름을 사용할 JS수 있습니다. 다음 코드는 ON 속성 이름을 사용하도록 SystemTextJsonValidationMetadataProviderJS유효성 검사를 구성합니다.

using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider());
});

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

다음 코드는 Json.NET 사용할 때 ON 속성 이름을 사용하도록 NewtonsoftJsonValidationMetadataProviderJS유효성 검사를 구성합니다.

using Microsoft.AspNetCore.Mvc.NewtonsoftJson;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new NewtonsoftJsonValidationMetadataProvider());
}).AddNewtonsoftJson();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

카멜 대/소문자를 사용하는 정책의 예는 GitHub를 참조Program.cs하세요.

Null을 허용하지 않는 참조 형식 및 [Required] 특성

유효성 검사 시스템은 Null을 허용하지 않는 매개 변수 또는 바인딩되는 속성을 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리합니다. Nullable 컨텍스트를 사용하도록 설정하면 MVC는 [Required(AllowEmptyStrings = true)] 특성을 사용하는 것처럼 암시적으로 null을 허용하지 않는 속성 또는 매개 변수의 유효성 검사를 시작합니다. 다음 코드를 살펴보세요.

public class Person
{
    public string Name { get; set; }
}

앱이 빌드<Nullable>enable</Nullable>된 경우 ON 또는 양식 게시에 JS대한 Name 값이 누락되면 유효성 검사 오류가 발생합니다. Null 허용 참조 형식을 사용하여 Name 속성에 null 또는 누락된 값을 지정할 수 있습니다.

public class Person
{
    public string? Name { get; set; }
}

Program.cs에서 SuppressImplicitRequiredAttributeForNonNullableReferenceTypes를 구성하여 이 동작을 사용하지 않도록 설정할 수 있습니다.

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

서버에 대한 [Required] 유효성 검사

서버에서 속성이 Null인 경우 필수 값이 없는 것으로 간주합니다. Null을 허용하지 않는 필드는 언제나 유효하며 [Required] 특성의 오류 메시지는 표시되지 않습니다.

그러나 Null을 허용하지 않는 속성에 대한 모델 바인딩이 실패하여 The value '' is invalid와 같은 오류 메시지가 표시될 수 있습니다. Null을 허용하지 않는 형식의 서버 쪽 유효성 검사에 대한 사용자 지정 오류 메시지를 지정하려는 경우 다음과 같은 방법이 있습니다.

  • 필드를 Null 허용으로 만듭니다(예: decimal 대신에 decimal?). Nullable< T> 값 형식은 표준 nullable 형식처럼 처리됩니다.

  • 다음 예제에서와 같이 모델 바인딩에 의해 사용할 기본 오류 메시지를 지정합니다.

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

    기본 메시지를 설정할 수 있는 모델 바인딩 오류에 대한 자세한 내용은 DefaultModelBindingMessageProvider를 참조하십시오.

클라이언트에 대한 [Required] 유효성 검사

클라이언트에서 Null을 허용하지 않는 형식 및 문자열은 서버의 경우와 다르게 처리됩니다. 클라이언트에서:

  • 값은 해당 값에 대한 입력이 있는 경우에만 존재하는 것으로 간주됩니다. 그러므로 클라이언트 쪽 유효성 검사에서는 Null을 허용하지 않는 형식을 Null 허용 형식과 동일하게 처리합니다.
  • 문자열 필드의 공백은 jQuery 유효성 검사 필수 메서드에 의해 유효한 입력으로 간주됩니다. 서버 쪽 유효성 검사에서는 공백만 입력된 경우 필수 문자열 필드를 잘못된 것으로 간주합니다.

위에서 설명했듯이 Null을 허용하지 않는 형식은 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리됩니다. 즉, [Required(AllowEmptyStrings = true)] 특성을 적용하지 않더라도 클라이언트 쪽 유효성 검사가 이루어집니다. 그러나 해당 특성을 사용하지 않으면 기본 오류 메시지가 표시됩니다. 사용자 지정 오류 메시지를 지정하려면 해당 특성을 사용하십시오.

[Remote] 특성

[원격] 특성은 필드 입력이 유효한지 여부를 확인하기 위해 서버에서 메서드를 호출해야 하는 클라이언트 쪽 유효성 검사를 구현합니다. 예를 들어 앱에서 사용자 이름을 이미 사용 중인지 여부를 확인해야 할 수 있습니다.

원격 유효성 검사를 구현하려면:

  1. JavaScript가 호출할 작업 메서드를 만듭니다. jQuery 유효성 검사 원격 메서드에는 ON 응답이 JS예상됩니다.

    • true는 입력 데이터가 유효함을 의미합니다.
    • false, undefined 또는 null은 입력이 잘못되었음을 의미합니다. 기본 오류 메시지를 표시합니다.
    • 다른 문자열은 모두 입력이 잘못되었음을 의미합니다. 문자열을 사용자 지정 오류 메시지로 표시합니다.

    다음은 사용자 지정 오류 메시지를 반환하는 작업 메서드의 예입니다.

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. 다음 예제와 같이 모델 클래스에서는 유효성 검사 작업 메서드를 가리키는 [Remote] 특성으로 속성에 주석을 답니다.

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; } = null!;
    

추가 필드

[Remote] 특성의 AdditionalFields 속성을 사용하여 서버의 데이터를 기준으로 필드 조합의 유효성을 검사할 수 있습니다. 예를 들어 User 모델이 FirstNameLastName 속성을 포함한 경우 해당 이름 쌍을 이미 가진 기존 사용자가 없는지 확인하는 것이 좋습니다. 다음 예제에서는 AdditionalFields을 사용하는 방법을 보여 줍니다.

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;

AdditionalFields는 명시적으로 믄자열 "FirstName" 및 "LastName"으로 설정할 수 있지만 nameof 연산자를 사용하면 나중에 리팩터링이 간단해집니다. 이 유효성 검사의 작업 메서드는 firstNamelastName 인수를 모두 허용해야 합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

사용자가 이름 또는 성을 입력하면 JavaScript에서는 원격 호출을 실행하여 해당 이름 쌍이 사용 중인지 확인합니다.

두 개 이상의 추가 필드에 대한 유효성을 검사하려면 해당 필드를 쉼표로 구분된 목록으로 제공합니다. 예를 들어 MiddleName 속성을 모델에 추가하려면 [Remote] 특성을 다음 예제와 같이 설정합니다.

[Remote(action: "VerifyName", controller: "Users",
    AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

모든 특성 인수와 같은 AdditionalFields은 상수 식이어야 합니다. 따라서 AdditionalFields를 초기화하기 위해 보간된 문자열을 사용하거나 Join을 호출하지 마십시오.

기본 제공 특성에 대한 대안

기본 제공 특성이 제공하지 않는 유효성 검사가 필요한 경우 다음과 같이 할 수 있습니다.

사용자 지정 특성

기본 제공 유효성 검사 특성이 처리하지 않는 시나리오의 경우 사용자 지정 유효성 검사 특성을 만들 수 있습니다. ValidationAttribute에서 상속하는 클래스를 만들고 IsValid 메서드를 재정의합니다.

IsValid 메서드에 대해서는 유효성을 검사할 입력인 이라는 개체를 지정할 수 있습니다. 또한 오버로드에 대해서는 모델 바인딩에 의해 생성된 모델 인스턴스와 같은 추가 정보를 제공하는 ValidationContext 개체를 지정할 수 있습니다.

다음 예제에서는 클래식 장르의 영화에 대한 개봉 날짜가 지정된 연도보다 이후가 아닌지 유효성을 검사합니다. [ClassicMovie] 특성:

  • 서버에서만 실행됩니다.
  • 클래식 동영상의 경우 릴리스 날짜의 유효성을 검사합니다.
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

위의 예제에서 movie 변수는 양식 제출에서 제공된 데이터를 포함하는 Movie 개체를 나타냅니다. 유효성 검사에 실패하면 오류 메시지가 발생하여 ValidationResult가 반환됩니다.

IValidatableObject

앞의 예제는 Movie 형식에 대해서만 작동합니다. 또 다른 클래스 수준 유효성 검사 방법은 다음 예제와 같이 모델 클래스 내에 IValidatableObject를 구현하는 것입니다.

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

최상위 노드 유효성 검사

최상위 수준 노드에는 다음이 포함됩니다.

  • 작업 매개 변수
  • 컨트롤러 속성
  • 페이지 처리기 매개 변수
  • 페이지 모델 속성

모델 바인딩 최상위 노드는 모델 속성의 유효성을 검사하는 것 외에도 유효성이 검사됩니다. 샘플 앱의 다음 예제에서 메서드는 VerifyPhone 작업 매개 변수의 RegularExpressionAttribute 유효성을 phone 검사하는 데 사용합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

최상위 노드는 유효성 검사 특성과 함께 BindRequiredAttribute를 사용할 수 있습니다. 샘플 앱CheckAge의 다음 예제에서 메서드는 양식이 age 제출될 때 매개 변수를 쿼리 문자열에서 바인딩해야 한다고 지정합니다.

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Check Age 페이지(CheckAge.cshtml)에는 두 가지 양식이 있습니다. 첫 번째 양식은 99Age 값을 쿼리 문자열 매개 변수(https://localhost:5001/Users/CheckAge?Age=99)로 제출합니다.

쿼리 문자열에서 올바른 서식이 지정된 age 매개 변수를 제출하면 양식이 유효성을 검사합니다.

기간 확인 페이지의 두 번째 양식은 요청 본문의 Age 값을 제출하고 유효성 검사가 실패합니다. age 매개 변수는 쿼리 문자열에서 가져와야 하므로 바인딩이 실패합니다.

최대 오류 수

유효성 검사는 최대 오류 수(기본값 200)에 도달하면 중지됩니다. Program.cs에 다음 코드로 이 번호를 구성할 수 있습니다.

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

builder.Services.AddSingleton
    <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

최대 재귀

ValidationVisitor는 유효성 검사 중인 모델의 개체 그래프를 트래버스합니다. 깊거나 무한히 재귀하는 모델의 경우 유효성 검사를 실행하면 스택 오버플로가 발생할 수 있습니다. MvcOptions.MaxValidationDepth 는 방문자 재귀가 구성된 깊이를 초과하는 경우 유효성 검사를 일찍 중지하는 방법을 제공합니다. MvcOptions.MaxValidationDepth의 기본값은 32입니다.

자동 단락

모델 그래프에 대한 유효성 검사가 필요하지 않은 경우 유효성 검사는 자동으로 단락됩니다(건너뜀). 런타임에 유효성 검사를 건너뛰는 개체로는 기본 형식(byte[], string[], Dictionary<string, string>) 수집 및 유효성 검사기를 포함하지 않은 복합 개체 그래프가 있습니다.

클라이언트 쪽 유효성 검사

클라이언트 쪽 유효성 검사는 형식이 유효할 때까지 전송을 방지합니다. 제출 단추는 형식을 전송하거나 오류 메시지를 표시하는 JavaScript를 실행합니다.

클라이언트 쪽 유효성 검사는 양식에 대한 입력 오류가 있는 경우 불필요한 서버 왕복을 방지합니다. 다음 스크립트는 클라이언트 쪽 유효성 검사를 참조 _Layout.cshtml 하고 _ValidationScriptsPartial.cshtml 지원합니다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>

jQuery 비간섭 유효성 검사 스크립트는 널리 사용되는 jQuery 유효성 검사 플러그 인에 기반한 사용자 지정 Microsoft 프런트 엔드 라이브러리입니다. jQuery 비간섭 유효성 검사를 사용하지 않을 경우 두 위치(모델 속성에 대한 서버 쪽 유효성 검사 특성에서 한 번 및 클라이언트 쪽 스크립트에서 다시 한 번)에서 동일한 유효성 검사 논리를 코딩해야 할 수 있습니다. 그 대신 태그 도우미HTML 도우미 는 유효성 검사가 필요한 양식 요소에 대해 모델 특성의 유효성 검사 특성 및 형식 메타데이터를 사용하여 HTML 5 data- 특성을 렌더링합니다. jQuery 비간섭 유효성 검사는 data- 특성을 구문 분석하고 jQuery 유효성 검사로 논리를 전달하여 효과적으로 서버 쪽 유효성 검사 논리를 클라이언트에 “복사”합니다. 다음과 같이 태그 도우미를 사용하여 클라이언트에서 유효성 검사 오류를 표시할 수 있습니다.

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

위의 태그 도우미는 다음 HTML을 렌더링합니다.

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

HTML의 data- 특성 출력은 Movie.ReleaseDate 속성에 대한 유효성 검사 특성에 해당합니다. data-val-required 특성은 사용자가 릴리스 날짜 필드를 입력하지 않았음을 표시하는 오류 메시지를 포함합니다. jQuery 눈에 거슬리지 않는 유효성 검사는 이 값을 jQuery Validation required() 메서드에 전달한 다음, 해당 메시지를 함께 <제공되는 범위> 요소에 표시합니다.

데이터 형식 유효성 검사는 [DataType] 특성으로 재정의되지 않는 한 속성의 .NET 형식을 기반으로 합니다. 브라우저는 고유한 기본 오류 메시지를 가지고 있지만 jQuery유효성 검사의 비간섭 유효성 검사 패키지는 해당 메시지를 재정의할 수 있습니다. [DataType] 특성 및 하위 클래스(예: [EmailAddress]) 를 사용하면 오류 메시지를 지정할 수 있습니다.

비간섭 유효성 검사

비간섭 유효성 검사에 대한 자세한 내용은 이 GitHub 문제를 참조하세요.

동적 형식에 유효성 검사 추가

jQuery 비간섭 유효성 검사는 페이지가 먼저 로드되는 경우 유효성 검사 논리 및 매개 변수를 jQuery 유효성 검사에 전달합니다. 따라서 동적으로 생성된 양식에 대해서는 유효성 검사가 자동으로 작동하지 않습니다. 유효성 검사를 사용하도록 설정하려면 jQuery 비간섭 유효성 검사에서 동적 폼을 만든 후에 즉시 구문 분석하도록 지시합니다. 예를 들어 다음 코드에서는 AJAX를 통해 추가된 양식에 대해 클라이언트 쪽 유효성 검사를 설정합니다.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

$.validator.unobtrusive.parse() 메서드는 하나의 인수에 대해 jQuery 선택기를 허용합니다. 이 메서드는 jQuery 비간섭 유효성 검사에서 해당 선택기 내에 있는 형식의 data- 특성을 구문 분석하도록 지시합니다. 그러면 이러한 특성 값이 jQuery 유효성 검사 플러그 인에 전달됩니다.

동적 컨트롤에 유효성 검사 추가

$.validator.unobtrusive.parse() 메서드는 <input><select/>와 같은 동적으로 생성된 개별 컨트롤이 아닌 전체 양식에 대해 작용합니다. 양식을 다시 구문 분석하려면 다음 예제와 같이 이전에 양식을 구문 분석했을 때 추가된 유효성 검사 데이터를 제거합니다.

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

사용자 지정 클라이언트 쪽 유효성 검사

사용자 지정 클라이언트 쪽 유효성 검사는 사용자 지정 jQuery 유효성 검사 어댑터에서 작동하는 data- HTML 특성을 생성하여 수행됩니다. 다음 샘플 어댑터 코드는 이 문서에서 이전에 소개한 [ClassicMovie][ClassicMovieWithClientValidator] 특성용으로 작성되었습니다.

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

어댑터 작성 방법에 대한 자세한 내용은 jQuery 유효성 검사 설명서를 참조하세요.

지정된 필드에 대한 어댑터 사용은 data- 특성에 의해 트리거됩니다.

  • 필드를 유효성 검사가 적용되는 것으로 표시합니다(data-val="true").
  • 유효성 검사 규칙 이름 및 오류 메시지 텍스트(예: data-val-rulename="Error message.")를 식별합니다.
  • 유효섬 검사기에 필요한 추가 매개 변수(예: data-val-rulename-param1="value")를 제공합니다.

다음 예제에서는 샘플 앱의ClassicMovie 특성에 대한 특성을 보여줍니다data-.

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

앞에서 설명했듯이 태그 도우미HTML 도우미는 유효성 검사 특성의 정보를 사용하여 data- 특성을 렌더링합니다. 사용자 지정 data- HTML 특성을 생성하는 코드를 작성하는 두 가지 방법이 있습니다.

  • AttributeAdapterBase<TAttribute>에서 파생하는 클래스 및 IValidationAttributeAdapterProvider를 구현하는 클래스를 만들고 사용자의 특성 및 해당 어댑터를 DI에 등록합니다. 이 메서드는 서버 관련 및 클라이언트 관련 유효성 검사 코드가 별도의 클래스에 있는 단일 책임 원칙 을 따릅니다. 또한 어댑터는 DI에 등록되어 있으므로 필요한 경우 DI의 다른 서비스를 사용할 수 있다는 장점이 있습니다.
  • 사용자의 ValidationAttribute 클래스에서 IClientModelValidator를 구현합니다. 이 방법은 특성이 서버 쪽 유효성 검사를 수행하지 않고 DI의 서비스가 필요하지 않은 경우 적절할 수 있습니다.

클라이언트 쪽 유효성 검사에 대한 특성 어댑터

HTML에서 특성을 렌더링하는 data- 이 방법은 샘플 앱ClassicMovie 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  1. 사용자 지정 유효성 검사 특성에 대한 특성 어댑터 클래스를 생성합니다. AttributeAdapterBase<TAttribute>에서 클래스를 파생합니다. 이 예제와 같이 렌더링된 출력에 data- 특성을 추가하는 AddValidation 메서드를 생성합니다.

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(
            ClassicMovieAttribute attribute, IStringLocalizer? stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
            => Attribute.GetErrorMessage();
    }
    
  2. IValidationAttributeAdapterProvider를 구현하는 어댑터 공급자 클래스를 생성합니다. GetAttributeAdapter 메서드에서 다음 예제와 같이 사용자 지정 특성을 어댑터의 생성자에 전달합니다.

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter? GetAttributeAdapter(
            ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. DI용 어댑터 공급자를 Program.cs에 등록합니다.

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

클라이언트 쪽 유효성 검사를 위한 IClientModelValidator

HTML에서 특성을 렌더링하는 data- 이 방법은 샘플 앱ClassicMovieWithClientValidator 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  • 사용자 지정 유효성 검사 특성에서 IClientModelValidator 인터페이스를 구현하고 AddValidation 메서드를 생성합니다. AddValidation 메서드에서 다음 예제와 같이 유효성 검사를 위한 data- 특성을 추가합니다.

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
            => Year = year;
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult? IsValid(
            object? value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value!).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정

다음 코드는 Razor Pages에서 클라이언트 유효성 검사를 사용하지 않도록 설정합니다.

builder.Services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정하는 다른 옵션:

  • 모든 파일에 대한 참조를 _ValidationScriptsPartial 주석으로 처리합니다 .cshtml .
  • Pages\Shared_ValidationScriptsPartial.cshtml 파일의 내용을 제거합니다.

앞의 접근 방식은 ASP.NET Core IdentityRazor 클래스 라이브러리의 클라이언트 쪽 유효성 검사를 방지하지 않습니다. 자세한 내용은 ASP.NET Core 프로젝트에서 Identity 스캐폴드를 참조하세요.

추가 리소스

이 문서에서는 ASP.NET Core MVC 또는 Razor Pages 앱에서 사용자 입력의 유효성을 검사하는 방법에 대해 설명합니다.

예제 코드 살펴보기 및 다운로드 (다운로드 방법). 다운로드 예제는 영역을 테스트하기 위한 기초적인 앱을 제공합니다.

모델 상태

모델 상태는 모델 바인딩 및 모델 유효성 검사 두 하위 시스템에서 발생하는 오류를 나타냅니다. 모델 바인딩에서 발생하는 오류는 일반적으로 데이터 변환 오류입니다. 예를 들어 정수 필드에 “x”가 입력됩니다. 모델 유효성 검사는 모델 바인딩 후에 발생하며 데이터가 비즈니스 규칙에 맞지 않으면 오류를 보고합니다. 예를 들어 1에서 5 사이의 등급을 필요한 필드에 0이 입력됩니다.

모델 바인딩과 모델 유효성 검사 모두 컨트롤러 작업 또는 Razor Pages 처리기 메서드를 실행하기 전에 실행됩니다. 웹앱의 경우 ModelState.IsValid를 검사하고 적절히 반응하는 기능은 앱에서 실행합니다. 일반적으로 웹앱은 페이지를 오류 메시지와 함께 다시 표시합니다.

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Web API 컨트롤러는 [ApiController] 특성이 있는지 확인할 ModelState.IsValid 필요가 없습니다. 이 경우 모델 상태가 잘못되면 오류 세부 정보를 포함하는 자동 HTTP 400 응답이 반환됩니다. 자세한 정보는 자동 HTTP 400 응답을 참조하세요.

유효성 검사 다시 실행

유효성 검사는 자동으로 실행 되지만 수동으로 반복하는 것이 좋습니다. 예를 들어 속성에 대한 값을 계산하고 해당 속성을 계산된 값으로 설정한 후 유효성 검사를 다시 실행하는 것이 좋습니다. 유효성 검사를 다시 실행하려면 ModelStateDictionary.ClearValidationState를 호출하여 TryValidateModel에 따라 유효성이 검사되는 모델에 대한 특정 유효성 검사를 제거합니다.

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

유효성 검사 특성

유효성 검사 특성을 사용하여 모델 속성에 대한 유효성 검사 규칙을 지정할 수 있습니다. 샘플 앱의 다음 예제에서는 유효성 검사 특성으로 주석이 추가된 모델 클래스를 보여줍니다. 특성은 [ClassicMovie] 사용자 지정 유효성 검사 특성이며 다른 특성은 기본 제공됩니다. 사용자 지정 특성을 구현하는 다른 방법을 보여 주는 [ClassicMovieWithClientValidator]는 표시되지 않습니다.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

기본 제공 특성

다음은 몇 가지 기본 제공 유효성 검사 특성입니다.

  • [ValidateNever]: 속성 또는 매개 변수를 유효성 검사에서 제외해야 임을 나타냅니다.
  • [신용 카드]: 속성에 신용 카드 형식이 있는지 확인합니다. jQuery 유효성 검사 추가 방법이 필요합니다.
  • [비교]: 모델의 두 속성이 일치하는지 확인합니다.
  • [EmailAddress]: 속성에 전자 메일 형식이 있는지 확인합니다.
  • [전화]: 속성에 전화 번호 형식이 지정되었는지 확인합니다.
  • [Range]: 속성 값이 지정된 범위 내에 속하는지 확인합니다.
  • [RegularExpression]: 속성 값이 지정된 정규식과 일치하는지 확인합니다.
  • [필수]: 필드가 null이 아닌지 확인합니다. 이 특성의 동작에 대한 자세한 내용은 [Required] 특성을 참조하세요.
  • [StringLength]: 문자열 속성 값이 지정된 길이 제한을 초과하지 않는지 확인합니다.
  • [URL]: 속성에 URL 형식이 있는지 확인합니다.
  • [원격]: 서버에서 작업 메서드를 호출하여 클라이언트에서 입력의 유효성을 검사합니다. 이 특성의 동작에 대한 자세한 내용은 [Remote] 특성을 참조하세요.

네임스페이스에서 System.ComponentModel.DataAnnotations 유효성 검사 특성의 전체 목록을 찾을 수 있습니다.

오류 메시지

유효성 검사 특성을 사용하여 잘못된 입력에 대해 표시할 오류 메시지를 지정할 수 있습니다. 예를 들어:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

내부적으로 이 특성은 필드 이름에 대한 자리 표시자 및 경우에 따라 추가 자리 표시자를 사용하여 String.Format을 호출합니다. 예를 들어:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Name 속성에 적용할 경우 위의 코드에 의해 생성되는 오류 메시지는 "이름의 길이는 6문자에서 8문자 사이여야 합니다"일 것입니다.

특정 특성의 오류 메시지에 대해 String.Format 에 전달되는 매개 변수를 알아보려면 DataAnnotations 소스 코드를 참조하세요.

Null을 허용하지 않는 참조 형식 및 [Required] 특성

유효성 검사 시스템은 Null을 허용하지 않는 매개 변수 또는 바인딩되는 속성을 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리합니다. Nullable 컨텍스트를 사용하도록 설정하면 MVC는 [Required(AllowEmptyStrings = true)] 특성을 사용하는 것처럼 암시적으로 null을 허용하지 않는 속성 또는 매개 변수의 유효성 검사를 시작합니다. 다음 코드를 살펴보세요.

public class Person
{
    public string Name { get; set; }
}

앱이 빌드<Nullable>enable</Nullable>된 경우 ON 또는 양식 게시에 JS대한 Name 값이 누락되면 유효성 검사 오류가 발생합니다. Null 허용 참조 형식을 사용하여 Name 속성에 null 또는 누락된 값을 지정할 수 있습니다.

public class Person
{
    public string? Name { get; set; }
}

Startup.ConfigureServices에서 SuppressImplicitRequiredAttributeForNonNullableReferenceTypes를 구성하여 이 동작을 사용하지 않도록 설정할 수 있습니다.

services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

서버에 대한 [Required] 유효성 검사

서버에서 속성이 Null인 경우 필수 값이 없는 것으로 간주합니다. Null을 허용하지 않는 필드는 언제나 유효하며 [Required] 특성의 오류 메시지는 표시되지 않습니다.

그러나 Null을 허용하지 않는 속성에 대한 모델 바인딩이 실패하여 The value '' is invalid와 같은 오류 메시지가 표시될 수 있습니다. Null을 허용하지 않는 형식의 서버 쪽 유효성 검사에 대한 사용자 지정 오류 메시지를 지정하려는 경우 다음과 같은 방법이 있습니다.

  • 필드를 Null 허용으로 만듭니다(예: decimal 대신에 decimal?). Nullable< T> 값 형식은 표준 nullable 형식처럼 처리됩니다.

  • 다음 예제에서와 같이 모델 바인딩에 의해 사용할 기본 오류 메시지를 지정합니다.

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

    기본 메시지를 설정할 수 있는 모델 바인딩 오류에 대한 자세한 내용은 DefaultModelBindingMessageProvider를 참조하십시오.

클라이언트에 대한 [Required] 유효성 검사

클라이언트에서 Null을 허용하지 않는 형식 및 문자열은 서버의 경우와 다르게 처리됩니다. 클라이언트에서:

  • 값은 해당 값에 대한 입력이 있는 경우에만 존재하는 것으로 간주됩니다. 그러므로 클라이언트 쪽 유효성 검사에서는 Null을 허용하지 않는 형식을 Null 허용 형식과 동일하게 처리합니다.
  • 문자열 필드의 공백은 jQuery 유효성 검사 필수 메서드에 의해 유효한 입력으로 간주됩니다. 서버 쪽 유효성 검사에서는 공백만 입력된 경우 필수 문자열 필드를 잘못된 것으로 간주합니다.

위에서 설명했듯이 Null을 허용하지 않는 형식은 [Required(AllowEmptyStrings = true)] 특성을 포함한 것처럼 처리됩니다. 즉, [Required(AllowEmptyStrings = true)] 특성을 적용하지 않더라도 클라이언트 쪽 유효성 검사가 이루어집니다. 그러나 해당 특성을 사용하지 않으면 기본 오류 메시지가 표시됩니다. 사용자 지정 오류 메시지를 지정하려면 해당 특성을 사용하십시오.

[Remote] 특성

[Remote] 특성은 서버에서 메서드를 호출하여 필드 입력이 유효한지 여부를 확인해야 하는 클라이언트 쪽 유효성 검사를 구현합니다. 예를 들어 앱에서 사용자 이름을 이미 사용 중인지 여부를 확인해야 할 수 있습니다.

원격 유효성 검사를 구현하려면:

  1. JavaScript가 호출할 작업 메서드를 만듭니다. jQuery 유효성 검사 원격 메서드에는 ON 응답이 JS예상됩니다.

    • true는 입력 데이터가 유효함을 의미합니다.
    • false, undefined 또는 null은 입력이 잘못되었음을 의미합니다. 기본 오류 메시지를 표시합니다.
    • 다른 문자열은 모두 입력이 잘못되었음을 의미합니다. 문자열을 사용자 지정 오류 메시지로 표시합니다.

    다음은 사용자 지정 오류 메시지를 반환하는 작업 메서드의 예입니다.

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. 다음 예제와 같이 모델 클래스에서는 유효성 검사 작업 메서드를 가리키는 [Remote] 특성으로 속성에 주석을 답니다.

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; }
    

추가 필드

[Remote] 특성의 AdditionalFields 속성을 사용하여 서버의 데이터를 기준으로 필드 조합의 유효성을 검사할 수 있습니다. 예를 들어 User 모델이 FirstNameLastName 속성을 포함한 경우 해당 이름 쌍을 이미 가진 기존 사용자가 없는지 확인하는 것이 좋습니다. 다음 예제에서는 AdditionalFields을 사용하는 방법을 보여 줍니다.

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; }

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; }

AdditionalFields는 명시적으로 믄자열 "FirstName" 및 "LastName"으로 설정할 수 있지만 nameof 연산자를 사용하면 나중에 리팩터링이 간단해집니다. 이 유효성 검사의 작업 메서드는 firstNamelastName 인수를 모두 허용해야 합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

사용자가 이름 또는 성을 입력하면 JavaScript에서는 원격 호출을 실행하여 해당 이름 쌍이 사용 중인지 확인합니다.

두 개 이상의 추가 필드에 대한 유효성을 검사하려면 해당 필드를 쉼표로 구분된 목록으로 제공합니다. 예를 들어 MiddleName 속성을 모델에 추가하려면 [Remote] 특성을 다음 예제와 같이 설정합니다.

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

모든 특성 인수와 같은 AdditionalFields은 상수 식이어야 합니다. 따라서 AdditionalFields를 초기화하기 위해 보간된 문자열을 사용하거나 Join을 호출하지 마십시오.

기본 제공 특성에 대한 대안

기본 제공 특성이 제공하지 않는 유효성 검사가 필요한 경우 다음과 같이 할 수 있습니다.

사용자 지정 특성

기본 제공 유효성 검사 특성이 처리하지 않는 시나리오의 경우 사용자 지정 유효성 검사 특성을 만들 수 있습니다. ValidationAttribute에서 상속하는 클래스를 만들고 IsValid 메서드를 재정의합니다.

IsValid 메서드에 대해서는 유효성을 검사할 입력인 이라는 개체를 지정할 수 있습니다. 또한 오버로드에 대해서는 모델 바인딩에 의해 생성된 모델 인스턴스와 같은 추가 정보를 제공하는 ValidationContext 개체를 지정할 수 있습니다.

다음 예제에서는 클래식 장르의 영화에 대한 개봉 날짜가 지정된 연도보다 이후가 아닌지 유효성을 검사합니다. [ClassicMovie] 특성:

  • 서버에서만 실행됩니다.
  • 클래식 동영상의 경우 릴리스 날짜의 유효성을 검사합니다.
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
    {
        Year = year;
    }

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

위의 예제에서 movie 변수는 양식 제출에서 제공된 데이터를 포함하는 Movie 개체를 나타냅니다. 유효성 검사에 실패하면 오류 메시지가 발생하여 ValidationResult가 반환됩니다.

IValidatableObject

앞의 예제는 Movie 형식에 대해서만 작동합니다. 또 다른 클래스 수준 유효성 검사 방법은 다음 예제와 같이 모델 클래스 내에 IValidatableObject를 구현하는 것입니다.

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

최상위 노드 유효성 검사

최상위 수준 노드에는 다음이 포함됩니다.

  • 작업 매개 변수
  • 컨트롤러 속성
  • 페이지 처리기 매개 변수
  • 페이지 모델 속성

모델 바인딩 최상위 노드는 모델 속성의 유효성을 검사하는 것 외에도 유효성이 검사됩니다. 샘플 앱의 다음 예제에서 메서드는 VerifyPhone 이 메서드를 RegularExpressionAttribute 사용하여 작업 매개 변수의 유효성을 phone 검사합니다.

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

최상위 노드는 유효성 검사 특성과 함께 BindRequiredAttribute를 사용할 수 있습니다. 샘플 앱CheckAge의 다음 예제에서 메서드는 양식이 age 제출될 때 매개 변수를 쿼리 문자열에서 바인딩해야 한다고 지정합니다.

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

검사 기간 페이지(CheckAge.cshtml)에는 두 가지 양식이 있습니다. 첫 번째 양식은 99Age 값을 쿼리 문자열 매개 변수(https://localhost:5001/Users/CheckAge?Age=99)로 제출합니다.

쿼리 문자열에서 올바른 서식이 지정된 age 매개 변수를 제출하면 양식이 유효성을 검사합니다.

기간 확인 페이지의 두 번째 양식은 요청 본문의 Age 값을 제출하고 유효성 검사가 실패합니다. age 매개 변수는 쿼리 문자열에서 가져와야 하므로 바인딩이 실패합니다.

최대 오류 수

유효성 검사는 최대 오류 수(기본값 200)에 도달하면 중지됩니다. Startup.ConfigureServices에 다음 코드로 이 번호를 구성할 수 있습니다.

services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

services.AddSingleton<IValidationAttributeAdapterProvider,
    CustomValidationAttributeAdapterProvider>();

최대 재귀

ValidationVisitor는 유효성 검사 중인 모델의 개체 그래프를 트래버스합니다. 깊거나 무한히 재귀하는 모델의 경우 유효성 검사를 실행하면 스택 오버플로가 발생할 수 있습니다. MvcOptions.MaxValidationDepth 는 방문자 재귀가 구성된 깊이를 초과하는 경우 유효성 검사를 조기에 중지하는 방법을 제공합니다. MvcOptions.MaxValidationDepth의 기본값은 32입니다.

자동 단락

모델 그래프에 대한 유효성 검사가 필요하지 않은 경우 유효성 검사는 자동으로 단락됩니다(건너뜀). 런타임에 유효성 검사를 건너뛰는 개체로는 기본 형식(byte[], string[], Dictionary<string, string>) 수집 및 유효성 검사기를 포함하지 않은 복합 개체 그래프가 있습니다.

클라이언트 쪽 유효성 검사

클라이언트 쪽 유효성 검사는 형식이 유효할 때까지 전송을 방지합니다. 제출 단추는 형식을 전송하거나 오류 메시지를 표시하는 JavaScript를 실행합니다.

클라이언트 쪽 유효성 검사는 양식에 대한 입력 오류가 있는 경우 불필요한 서버 왕복을 방지합니다. 다음 스크립트는 클라이언트 쪽 유효성 검사를 참조 _Layout.cshtml 하고 _ValidationScriptsPartial.cshtml 지원합니다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js"></script>

jQuery 비간섭 유효성 검사 스크립트는 널리 사용되는 jQuery 유효성 검사 플러그 인에 기반한 사용자 지정 Microsoft 프런트 엔드 라이브러리입니다. jQuery 비간섭 유효성 검사를 사용하지 않을 경우 두 위치(모델 속성에 대한 서버 쪽 유효성 검사 특성에서 한 번 및 클라이언트 쪽 스크립트에서 다시 한 번)에서 동일한 유효성 검사 논리를 코딩해야 할 수 있습니다. 그 대신 태그 도우미HTML 도우미 는 유효성 검사가 필요한 양식 요소에 대해 모델 특성의 유효성 검사 특성 및 형식 메타데이터를 사용하여 HTML 5 data- 특성을 렌더링합니다. jQuery 비간섭 유효성 검사는 data- 특성을 구문 분석하고 jQuery 유효성 검사로 논리를 전달하여 효과적으로 서버 쪽 유효성 검사 논리를 클라이언트에 “복사”합니다. 다음과 같이 태그 도우미를 사용하여 클라이언트에서 유효성 검사 오류를 표시할 수 있습니다.

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

위의 태그 도우미는 다음 HTML을 렌더링합니다.

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

HTML의 data- 특성 출력은 Movie.ReleaseDate 속성에 대한 유효성 검사 특성에 해당합니다. data-val-required 특성은 사용자가 릴리스 날짜 필드를 입력하지 않았음을 표시하는 오류 메시지를 포함합니다. jQuery 눈에 거슬리지 않는 유효성 검사에서는 이 값을 jQuery Validation required() 메서드에 전달한 다음, 해당 메시지를 해당 <범위> 요소에 표시합니다.

데이터 형식 유효성 검사는 [DataType] 특성으로 재정의되지 않는 한 속성의 .NET 형식을 기반으로 합니다. 브라우저는 고유한 기본 오류 메시지를 가지고 있지만 jQuery유효성 검사의 비간섭 유효성 검사 패키지는 해당 메시지를 재정의할 수 있습니다. [DataType] 특성 및 [EmailAddress] 와 같은 서브클래스를 사용하여 오류 메시지를 지정할 수 있습니다.

비간섭 유효성 검사

비간섭 유효성 검사에 대한 자세한 내용은 이 GitHub 문제를 참조하세요.

동적 형식에 유효성 검사 추가

jQuery 비간섭 유효성 검사는 페이지가 먼저 로드되는 경우 유효성 검사 논리 및 매개 변수를 jQuery 유효성 검사에 전달합니다. 따라서 동적으로 생성된 양식에 대해서는 유효성 검사가 자동으로 작동하지 않습니다. 유효성 검사를 사용하도록 설정하려면 jQuery 비간섭 유효성 검사에서 동적 폼을 만든 후에 즉시 구문 분석하도록 지시합니다. 예를 들어 다음 코드에서는 AJAX를 통해 추가된 양식에 대해 클라이언트 쪽 유효성 검사를 설정합니다.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

$.validator.unobtrusive.parse() 메서드는 하나의 인수에 대해 jQuery 선택기를 허용합니다. 이 메서드는 jQuery 비간섭 유효성 검사에서 해당 선택기 내에 있는 형식의 data- 특성을 구문 분석하도록 지시합니다. 그러면 이러한 특성 값이 jQuery 유효성 검사 플러그 인에 전달됩니다.

동적 컨트롤에 유효성 검사 추가

$.validator.unobtrusive.parse() 메서드는 <input><select/>와 같은 동적으로 생성된 개별 컨트롤이 아닌 전체 양식에 대해 작용합니다. 양식을 다시 구문 분석하려면 다음 예제와 같이 이전에 양식을 구문 분석했을 때 추가된 유효성 검사 데이터를 제거합니다.

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

사용자 지정 클라이언트 쪽 유효성 검사

사용자 지정 클라이언트 쪽 유효성 검사는 사용자 지정 jQuery 유효성 검사 어댑터에서 작동하는 data- HTML 특성을 생성하여 수행됩니다. 다음 샘플 어댑터 코드는 이 문서에서 이전에 소개한 [ClassicMovie][ClassicMovieWithClientValidator] 특성용으로 작성되었습니다.

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

어댑터 작성 방법에 대한 자세한 내용은 jQuery 유효성 검사 설명서를 참조하세요.

지정된 필드에 대한 어댑터 사용은 data- 특성에 의해 트리거됩니다.

  • 필드를 유효성 검사가 적용되는 것으로 표시합니다(data-val="true").
  • 유효성 검사 규칙 이름 및 오류 메시지 텍스트(예: data-val-rulename="Error message.")를 식별합니다.
  • 유효섬 검사기에 필요한 추가 매개 변수(예: data-val-rulename-param1="value")를 제공합니다.

다음 예제에서는 샘플 앱의ClassicMovie 특성에 대한 특성을 보여줍니다data-.

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

앞에서 설명했듯이 태그 도우미HTML 도우미는 유효성 검사 특성의 정보를 사용하여 data- 특성을 렌더링합니다. 사용자 지정 data- HTML 특성을 생성하는 코드를 작성하는 두 가지 방법이 있습니다.

  • AttributeAdapterBase<TAttribute>에서 파생하는 클래스 및 IValidationAttributeAdapterProvider를 구현하는 클래스를 만들고 사용자의 특성 및 해당 어댑터를 DI에 등록합니다. 이 메서드는 서버 관련 및 클라이언트 관련 유효성 검사 코드가 별도의 클래스에 있다는 단일 책임 원칙 을 따릅니다. 또한 어댑터는 DI에 등록되어 있으므로 필요한 경우 DI의 다른 서비스를 사용할 수 있다는 장점도 있습니다.
  • 사용자의 ValidationAttribute 클래스에서 IClientModelValidator를 구현합니다. 이 방법은 특성이 서버 쪽 유효성 검사를 수행하지 않고 DI의 서비스가 필요하지 않은 경우 적절할 수 있습니다.

클라이언트 쪽 유효성 검사에 대한 특성 어댑터

HTML에서 특성을 렌더링하는 data- 이 메서드는 샘플 앱ClassicMovie 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  1. 사용자 지정 유효성 검사 특성에 대한 특성 어댑터 클래스를 생성합니다. AttributeAdapterBase<TAttribute>에서 클래스를 파생합니다. 이 예제와 같이 렌더링된 출력에 data- 특성을 추가하는 AddValidation 메서드를 생성합니다.

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute,
            IStringLocalizer stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext) =>
            Attribute.GetErrorMessage();
    }
    
  2. IValidationAttributeAdapterProvider를 구현하는 어댑터 공급자 클래스를 생성합니다. GetAttributeAdapter 메서드에서 다음 예제와 같이 사용자 지정 특성을 어댑터의 생성자에 전달합니다.

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute,
            IStringLocalizer stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. DI용 어댑터 공급자를 Startup.ConfigureServices에 등록합니다.

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

클라이언트 쪽 유효성 검사를 위한 IClientModelValidator

HTML에서 특성을 렌더링하는 data- 이 메서드는 샘플 앱ClassicMovieWithClientValidator 특성에서 사용됩니다. 이 방법을 사용하여 클라이언트 유효성 검사를 추가하려면:

  • 사용자 지정 유효성 검사 특성에서 IClientModelValidator 인터페이스를 구현하고 AddValidation 메서드를 생성합니다. AddValidation 메서드에서 다음 예제와 같이 유효성 검사를 위한 data- 특성을 추가합니다.

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
        {
            Year = year;
        }
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult IsValid(object value,
            ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정

다음 코드는 Razor Pages에서 클라이언트 유효성 검사를 사용하지 않도록 설정합니다.

services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

클라이언트 쪽 유효성 검사를 사용하지 않도록 설정하는 다른 옵션:

  • 모든 파일에 대한 참조를 _ValidationScriptsPartial 주석으로 처리합니다 .cshtml .
  • Pages\Shared_ValidationScriptsPartial.cshtml 파일의 내용을 제거합니다.

앞의 방법은 ASP.NET Core IdentityRazor 클래스 라이브러리의 클라이언트 쪽 유효성 검사를 방지하지 않습니다. 자세한 내용은 ASP.NET Core 프로젝트에서 Identity 스캐폴드를 참조하세요.

추가 리소스