다음을 통해 공유


유효성 검사

이 콘텐츠는 ‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ eBook에서 발췌한 것으로, .NET Docs에서 제공되거나 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공됩니다.

‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ eBook 표지 썸네일.

사용자의 입력을 수락하는 모든 앱은 입력이 유효한지 확인해야 합니다. 예를 들어 앱은 특정 범위의 문자만 포함하거나, 특정 길이이거나, 특정 형식과 일치하는 입력을 확인할 수 있습니다. 사용자는 유효성 검사 없이 앱 실패를 야기하는 데이터를 제공할 수 있습니다. 적절한 유효성 검사는 비즈니스 규칙을 적용하며 공격자의 악의적 데이터 삽입을 방지하는 데 도움이 될 수 있습니다.

MVVM(Model-View-ViewModel) 패턴의 컨텍스트에서 뷰 모델 또는 모델은 종종 데이터 유효성 검사를 수행하고 사용자가 오류를 수정할 수 있도록 뷰에 유효성 검사 오류 신호를 보내야 합니다. eShop 다중 플랫폼 앱은 뷰 모델 속성의 동기 클라이언트 쪽 유효성 검사를 수행하고 잘못된 데이터가 포함된 컨트롤을 강조 표시하고 데이터가 잘못된 이유를 사용자에게 알리는 오류 메시지를 표시하여 유효성 검사 오류를 사용자에게 알릴 수 있습니다. 아래 이미지는 eShop 다중 플랫폼 앱에서 유효성 검사를 수행하는 데 관련된 클래스를 보여 줍니다.

eShop 다중 플랫폼 앱의 유효성 검사 클래스입니다.

유효성 검사가 필요한 뷰 모델 속성은 ValidatableObject<T> 형식이며, 각 ValidatableObject<T> 인스턴스에는 해당 Validations 속성에 유효성 검사 규칙이 추가됩니다. 유효성 검사는 유효성 검사 규칙을 검색하고 ValidatableObject<T>.Value 속성에 대해 해당 규칙을 실행하는 ValidatableObject<T> 인스턴스의 Validate 메서드를 호출하여 뷰 모델에서 호출됩니다. 유효성 검사 오류는 ValidatableObject<T> 인스턴스의 Errors 속성에 배치되며 ValidatableObject<T> 인스턴스의 IsValid 속성은 유효성 검사가 성공했는지 여부를 나타내도록 업데이트됩니다. 다음 코드에서는 ValidatableObject<T>의 구현을 보여 줍니다.

using CommunityToolkit.Mvvm.ComponentModel;
namespace eShop.Validations;
public class ValidatableObject<T> : ObservableObject, IValidity
{
    private IEnumerable<string> _errors;
    private bool _isValid;
    private T _value;
    public List<IValidationRule<T>> Validations { get; } = new();
    public IEnumerable<string> Errors
    {
        get => _errors;
        private set => SetProperty(ref _errors, value);
    }
    public bool IsValid
    {
        get => _isValid;
        private set => SetProperty(ref _isValid, value);
    }
    public T Value
    {
        get => _value;
        set => SetProperty(ref _value, value);
    }
    public ValidatableObject()
    {
        _isValid = true;
        _errors = Enumerable.Empty<string>();
    }
    public bool Validate()
    {
        Errors = Validations
            ?.Where(v => !v.Check(Value))
            ?.Select(v => v.ValidationMessage)
            ?.ToArray()
            ?? Enumerable.Empty<string>();
        IsValid = !Errors.Any();
        return IsValid;
    }
}

속성 변경 알림은 ObservableObject 클래스에서 제공되므로 Entry 컨트롤이 뷰 모델 클래스에 있는 ValidatableObject<T> 인스턴스의 IsValid 속성에 바인딩되어 입력한 데이터가 유효한지 여부에 대해 알림을 받을 수 있습니다.

유효성 검사 규칙 지정

유효성 검사 규칙은 다음 코드 예제에 표시된 IValidationRule<T> 인터페이스에서 파생되는 클래스를 만들어 지정합니다.

public interface IValidationRule<T>
{
    string ValidationMessage { get; set; }
    bool Check(T value);
}

이 인터페이스는 유효성 검사 규칙 클래스가 필요한 유효성 검사를 수행하는 데 사용되는 부울 Check 메서드, 유효성 검사가 실패할 경우 표시되는 유효성 검사 오류 메시지 값인 ValidationMessage 속성을 제공해야 한다고 지정합니다.

다음 코드 예제에서는 eShop 다중 플랫폼 앱에서 모의 서비스를 사용할 때 사용자가 LoginView 입력한 사용자 이름 및 암호의 유효성 검사를 수행하는 데 사용되는 유효성 검사 규칙을 보여 IsNotNullOrEmptyRule<T> 줍니다.

public class IsNotNullOrEmptyRule<T> : IValidationRule<T>
{
    public string ValidationMessage { get; set; }

    public bool Check(T value) =>
        value is string str && !string.IsNullOrWhiteSpace(str);
}

Check 메서드는 값 인수가 null인지, 비어 있는지 또는 공백 문자로만 구성되는지를 나타내는 부울을 반환합니다.

eShop 다중 플랫폼 앱에서는 사용되지 않지만 다음 코드 예제에서는 전자 메일 주소의 유효성을 검사하기 위한 유효성 검사 규칙을 보여 줍니다.

public class EmailRule<T> : IValidationRule<T>
{
    private readonly Regex _regex = new(@"^([w.-]+)@([w-]+)((.(w){2,3})+)$");

    public string ValidationMessage { get; set; }

    public bool Check(T value) =>
        value is string str && _regex.IsMatch(str);
}

Check 메서드는 값 인수가 유효한 메일 주소인지 여부를 나타내는 부울을 반환합니다. 이 작업은 Regex 생성자에 지정된 정규식 패턴이 처음 나오는 경우에 대한 값 인수를 검색하여 수행됩니다. 입력 문자열에서 정규식 패턴이 발견되었는지 여부는 valueRegex.IsMatch에 대해 확인하여 알아볼 수 있습니다.

참고

속성 유효성 검사에는 종속 속성이 포함되는 경우가 있습니다. 종속 속성의 예는 속성 A의 유효한 값 집합이 속성 B에 설정된 특정 값에 따라 달라지는 경우입니다. 속성 A의 값이 허용되는 값 중 하나인지 확인하기 위해 속성 B의 값을 검색하게 됩니다. 또한 속성 B의 값이 변경되면 속성 A의 유효성을 다시 검사해야 합니다.

속성에 유효성 검사 규칙 추가

eShop 다중 플랫폼 앱에서 유효성 검사가 필요한 보기 모델 속성은 유효성을 검사할 데이터의 형식인 형식 ValidatableObject<T>T 으로 선언됩니다. 다음 코드 예제에서는 이러한 두 속성의 예를 보여 줍니다.

public ValidatableObject<string> UserName { get; private set; }
public ValidatableObject<string> Password { get; private set; }

유효성 검사를 수행하려면 다음 코드 예제와 같이 각 ValidatableObject<T> 인스턴스의 유효성 검사 컬렉션에 유효성 검사 규칙을 추가해야 합니다.

private void AddValidations()
{
    UserName.Validations.Add(new IsNotNullOrEmptyRule<string> 
    { 
        ValidationMessage = "A username is required." 
    });

    Password.Validations.Add(new IsNotNullOrEmptyRule<string> 
    { 
        ValidationMessage = "A password is required." 
    });
}

이 메서드는 IsNotNullOrEmptyRule<T> 유효성 검사 규칙을 각 ValidatableObject<T> 인스턴스의 Validations 컬렉션에 추가하고, 유효성 검사가 실패할 경우 표시될 유효성 검사 오류 메시지를 지정하는 유효성 검사 규칙의 ValidationMessage 속성 값을 지정합니다.

유효성 검사 트리거

eShop 다중 플랫폼 앱에서 사용되는 유효성 검사 방법은 속성의 유효성 검사를 수동으로 트리거하고 속성이 변경되면 유효성 검사를 자동으로 트리거할 수 있습니다.

수동으로 유효성 검사 트리거

뷰 모델 속성에 대해 유효성 검사를 수동으로 트리거할 수 있습니다. 예를 들어 이는 사용자가 모의 서비스를 사용할 때 eShop 다중 플랫폼 앱에서 LoginView해당 단추를 탭 Login 할 때 발생합니다. 명령 대리자는 LoginViewModel에서 MockSignInAsync 메서드를 호출합니다. 그러면 다음 코드 예제에 표시된 Validate 메서드를 실행하여 유효성 검사가 호출됩니다.

private bool Validate()
{
    bool isValidUser = ValidateUserName();
    bool isValidPassword = ValidatePassword();
    return isValidUser && isValidPassword;
}

private bool ValidateUserName()
{
    return _userName.Validate();
}

private bool ValidatePassword()
{
    return _password.Validate();
}

Validate 메서드는 ValidatableObject<T> 인스턴스에서 Validate 메서드를 호출하여 LoginView에서 사용자가 입력한 사용자 이름 및 암호의 유효성 검사를 수행합니다. 다음 코드 예제에서는 ValidatableObject<T> 클래스의 Validate 메서드를 보여 줍니다.

public bool Validate()
{
    Errors = _validations
        ?.Where(v => !v.Check(Value))
        ?.Select(v => v.ValidationMessage)
        ?.ToArray()
        ?? Enumerable.Empty<string>();

    IsValid = !Errors.Any();

    return IsValid;
}

이 메서드는 개체의 Validations 컬렉션에 추가된 유효성 검사 규칙을 검색합니다. 검색된 각 유효성 검사 규칙에 대한 Check 메서드가 실행되고, 데이터의 유효성 검사가 실패한 모든 유효성 검사 규칙에 대한 ValidationMessage 속성 값이 ValidatableObject<T> 인스턴스의 Errors 컬렉션에 추가됩니다. 마지막으로 IsValid 속성이 설정되고 해당 값이 호출 메서드로 반환되어 유효성 검사의 성공 여부를 나타냅니다.

속성이 변경되면 유효성 검사 트리거

또한 바인딩된 속성이 변경될 때마다 유효성 검사가 자동으로 트리거됩니다. 예를 들어 LoginView의 양방향 바인딩이 UserName 또는 Password 속성을 설정하면 유효성 검사가 트리거됩니다. 다음 코드 예제에서는 이 작업이 발생하는 방법을 보여 줍니다.

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
    <Entry.Behaviors>
        <behaviors:EventToCommandBehavior
            EventName="TextChanged"
            Command="{Binding ValidateUserNameCommand}" />
    </Entry.Behaviors>
</Entry>

Entry 컨트롤은 ValidatableObject<T> 인스턴스의 UserName.Value 속성에 바인딩되고 컨트롤의 Behaviors 컬렉션에는 EventToCommandBehavior 인스턴스가 추가됩니다. 이 동작은 Entry의 텍스트가 변경될 때 발생하는 Entry에서 발생하는 TextChanged 이벤트에 대한 응답으로 ValidateUserNameCommand를 실행합니다. 차례로 ValidateUserNameCommand 대리자는 ValidatableObject<T> 인스턴스에 대해 Validate 메서드를 실행하는 ValidateUserName 메서드를 실행합니다. 따라서 사용자가 사용자 이름에 대한 Entry 컨트롤에 문자를 입력할 때마다 입력한 데이터의 유효성 검사가 수행됩니다.

유효성 검사 오류 표시

eShop 다중 플랫폼 앱은 빨간색 배경이 있는 잘못된 데이터가 포함된 컨트롤을 강조 표시하고 잘못된 데이터가 포함된 컨트롤 아래에 데이터가 잘못된 이유를 사용자에게 알리는 오류 메시지를 표시하여 유효성 검사 오류를 사용자에게 알릴 수 있습니다. 잘못된 데이터가 수정되면 백그라운드가 다시 기본 상태로 변경되고 오류 메시지가 제거됩니다. 아래 LoginView 이미지는 유효성 검사 오류가 있는 경우 eShop 다중 플랫폼 앱에 표시됩니다.

로그인하는 동안 유효성 검사 오류 표시

잘못된 데이터가 포함된 컨트롤 강조 표시

.NET MAUI는 최종 사용자에게 유효성 검사 정보를 제공하는 여러 가지 방법을 제공하지만 가장 편리한 방법 중 하나는 Triggers를 사용하는 것입니다. Triggers는 컨트롤에 대해 발생하는 이벤트 또는 데이터 변경에 따라 일반적으로 모양에 맞게 컨트롤의 상태를 변경하는 방법을 제공합니다. 유효성 검사를 위해 바인딩된 속성에서 발생한 변경 내용을 수신 대기하고 변경 내용에 응답하는 DataTrigger을 사용합니다. LoginViewEntry 컨트롤은 다음 코드를 사용하여 설정됩니다.

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
    <Entry.Style>
        <OnPlatform x:TypeArguments="Style">
            <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
            <On Platform="WinUI" Value="{StaticResource WinUIEntryStyle}" />
        </OnPlatform>
    </Entry.Style>
    <Entry.Behaviors>
        <mct:EventToCommandBehavior
            EventName="TextChanged"
            Command="{Binding ValidateCommand}" />
    </Entry.Behaviors>
    <Entry.Triggers>
        <DataTrigger 
            TargetType="Entry"
            Binding="{Binding UserName.IsValid}"
            Value="False">
            <Setter Property="BackgroundColor" Value="{StaticResource ErrorColor}" />
        </DataTrigger>
    </Entry.Triggers>
</Entry>

DataTrigger는 다음 속성을 지정합니다.

속성 설명
TargetType 트리거가 속한 컨트롤 형식입니다.
Binding 트리거 조건에 대한 변경 알림 및 값을 제공하는 데이터 Binding 태그입니다.
Value 트리거의 조건이 충족되는 경우를 지정하는 데이터 값입니다.

Entry에서는 LoginViewModel.UserName.IsValid 속성에 대한 변경 내용을 수신 대기합니다. 이 속성이 변경될 때마다 Value에 설정된 DataTrigger 속성과 해당 값이 비교됩니다. 값이 같으면 트리거 조건이 충족되고 DataTrigger에 제공된 모든 Setter 개체가 실행됩니다. 이 컨트롤에는 BackgroundColor 속성을 StaticResource 태그를 사용하여 정의된 사용자 지정 색으로 업데이트하는 단일 Setter 개체가 있습니다. Trigger 조건이 더 이상 충족되지 않으면 컨트롤은 Setter 개체로 설정된 속성을 이전 상태로 되돌립니다. Triggers에 대한 자세한 내용은 .NET MAUI Docs: 트리거를 참조하세요.

오류 메시지 표시

UI는 데이터 유효성 검사가 실패한 각 컨트롤 아래에 Label 컨트롤의 유효성 검사 오류 메시지를 표시합니다. 다음 코드 예제에서는 사용자가 유효한 사용자 이름을 입력하지 않은 경우 유효성 검사 오류 메시지를 표시하는 Label을 보여 줍니다.

<Label
    Text="{Binding UserName.Errors, Converter={StaticResource FirstValidationErrorConverter}"
    Style="{StaticResource ValidationErrorLabelStyle}" />

각 레이블은 유효성을 검사할 뷰 모델 개체의 Errors 속성에 바인딩됩니다. Errors 속성은 ValidatableObject<T> 클래스에서 제공되며 IEnumerable<string> 형식입니다. Errors 속성에는 여러 유효성 검사 오류가 포함될 수 있으므로 FirstValidationErrorConverter 인스턴스를 사용하여 표시를 위해 컬렉션에서 첫 번째 오류를 검색합니다.

요약

eShop 다중 플랫폼 앱은 뷰 모델 속성의 동기 클라이언트 쪽 유효성 검사를 수행하고 잘못된 데이터가 포함된 컨트롤을 강조 표시하고 데이터가 잘못된 이유를 사용자에게 알리는 오류 메시지를 표시하여 유효성 검사 오류를 사용자에게 알릴 수 있습니다.

유효성 검사가 필요한 뷰 모델 속성은 ValidatableObject<T> 형식이며, 각 ValidatableObject<T> 인스턴스에는 해당 Validations 속성에 유효성 검사 규칙이 추가됩니다. 유효성 검사는 유효성 검사 규칙을 검색하고 ValidatableObject<T> Value 속성에 대해 해당 규칙을 실행하는 ValidatableObject<T> 인스턴스의 Validate 메서드를 호출하여 뷰 모델에서 호출됩니다. 유효성 검사 오류는 ValidatableObject<T> 인스턴스의 Errors 속성에 배치되며 ValidatableObject<T> 인스턴스의 IsValid 속성은 유효성 검사가 성공했는지 여부를 나타내도록 업데이트됩니다.