사용자 지정 ValidationAttribute 및 Blazor 유효성 검사
# 모든 것을 맞춤설정하세요
아마도 내 모든 게시물에서 보셨겠지만 저는 이미 사용자 정의 속성, 사용자 정의 예외 처리, 서비스 컬렉션 주입 등에 관한 게시물을 작성했기 때문에 모든 것을 가능한 한 깔끔하게 유지하려고 노력합니다.
나는 이런 종류의 코딩 방식이 나와 내 팀에게 초과 근무 시간을 개선하고, 문제를 더 쉽게 찾고, 코드를 최대한 분리할 수 있는 방법을 제공한다는 것을 시간이 지나면서 깨달았습니다.
네, 이 멋진 이야기를 마치고 지금 여러분을 모시고 있습니다. 저는 최근 평소처럼 Blazor를 작업해 왔으며 수년 간의 개발 끝에 사용자 지정 유효성 검사 속성을 만들 수 있다는 것을 발견했습니다.
응, 웃기네, 몇년이 지나서야…
사용자 정의 유효성 검사 속성
아이디어는 실제로 작업에서 나왔습니다. 우리는 항상 모든 곳에서 유효성 검사를 수행하지만 동일한 유효성 검사 프로세스가 필요한 일부 필드가 있었기 때문에 거기에 뭔가가 있을 수 있다고 생각했습니다…. 사용자 정의 유효성 검사 속성과 같은 것입니다!
그래서 이에 대한 Microsoft 문서를 실행한 후 다음과 같이 사용자 지정 유효성 검사 특성을 만들고 속성에 할당할 수 있다는 것을 알게 되었습니다.
public class StringLengthRangeAttribute : ValidationAttribute
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public StringLengthRangeAttribute()
{
this.Minimum = 0;
this.Maximum = int.MaxValue;
}
public override bool IsValid(object value)
{
string strValue = value as string;
if (!string.IsNullOrEmpty(strValue))
{
int len = strValue.Length;
return len >= this.Minimum && len <= this.Maximum;
}
return true;
}
}
다음과 같은 간단한 클래스에서 사용하세요.
[Required]
[StringLengthRange(Minimum = 10, ErrorMessage = "Must be >10 characters.")]
[StringLengthRange(Maximum = 20)]
[Required]
[StringLengthRange(Minimum = 10, Maximum = 20)]
사용자 정의 유효성 검사기
그래서 저는 9개의 숫자와 하이픈으로 끝나는 20개의 첫 번째 문자를 계산하고 일반적으로 국가 코드가 되는 2개의 문자로 끝나는 특정 비즈니스 사례에 필요한 유효성 검사기를 가지고 있습니다. 123456789-123456789-ES
나는 결국 다음과 같은 결과를 얻었습니다. 정말 간단하지만 작동합니다.
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
public class SpecialStringValidatorAttribute : ValidationAttribute
{
private const int TotalLength = 22;
private const string Pattern = @"^(\d{10})-(\d{10})-([A-Za-z]{2})$";
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string strValue = value as string;
if (!string.IsNullOrEmpty(strValue))
{
if (strValue.Length != TotalLength)
{
return new ValidationResult($"The string must be {TotalLength} characters long.");
}
if (!Regex.IsMatch(strValue, Pattern))
{
return new ValidationResult("The string must follow the pattern: 1234567890-1234567890-AB");
}
return ValidationResult.Success;
}
return new ValidationResult("The string cannot be null or empty.");
}
}
테스트
만일의 경우를 대비해 나는 그들을 위해 몇 가지 테스트도 작성했습니다.
public class SpecialStringValidatorTests
{
[Theory]
[InlineData("1234567890-1234567890-AB", true)]
[InlineData("1234567890-1234567890-XY", true)]
[InlineData("1234567890-1234567890-A1", false)]
[InlineData("1234567890-1234567890-A", false)]
[InlineData("1234567890-123456789-AB", false)]
[InlineData("1234567890-1234567890", false)]
[InlineData("1234567890-1234567890-ABCDE", false)]
public void SpecialStringValidatorTest(string input, bool expectedResult)
{
// Arrange
var validator = new SpecialStringValidatorAttribute();
// Act
var result = validator.IsValid(input);
// Assert
Assert.Equal(expectedResult, result);
}
}
그리고 실행해보니 다음과 같은 결과가 나왔습니다.
Microsoft (R) Test Execution Command Line Tool Version 16.9.1
Copyright (c) Microsoft Corporation. All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Test run in progress...
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-AB", expectedResult: True)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-XY", expectedResult: True)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-A1", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-A", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-123456789-AB", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-ABCDE", expectedResult: False)
Test Run Successful.
Total tests: 7
Passed: 7
Total time: 1.7296 Seconds
사용자 정의 유효성 검사 및 Blazor
이제 그의 것을 사용할 수 있다는 것을 알았으니 Blazor에 구현하는 것이 확실히 좋은 생각이겠죠?
이전에 보여드린 Person 모델을 사용하는 다음 양식이 있다고 가정해 보겠습니다.
@using Models
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
<EditForm Model=@Person FormName="PersonForm">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="form-group">
<label for="Name">Name</label>
<InputText @bind-Value=Person.Name class="form-control" id="Name" />
<ValidationMessage For="() => Person.Name"/>
</div>
<div class="form-group">
<label for="MySpecialString">My special string</label>
<InputText @bind-Value=Person.MySpecialString class="form-control" id="Name" />
<ValidationMessage For="() => Person.MySpecialString"/>
</div>
<div class="form-group">
<label for="Age">Age</label>
<InputNumber @bind-Value=Person.Age class="form-control" id="Age" />
<ValidationMessage For=@(() => Person.Age) />
</div>
<input type="submit" class="btn btn-primary" value="Save"/>
</EditForm>
@code {
Person Person = new Person();
}
이것을 실행하자마자 다음과 같은 오류가 발생합니다.

그리고 우리가 원하는 것을 넣으면 다음과 같은 결과가 나옵니다.

솔직히 말해서 최소한 해당 양식의 유효성을 검사하는 논리를 사용자 정의 유효성 검사 속성으로 옮겨야 한다는 점은 매우 분명합니다. 그러면 해당 로그인에 대한 코드를 한 곳에 자유롭게 저장할 수 있으며 나중에 API나 다른 애플리케이션에 사용할 수 있습니다.
재미있게 보셨기를 바라며, 궁금하신 점이나 연락하고 싶으신 점이 있으시면 주저하지 마시고 연락주세요!