Computer >> 컴퓨터 >  >> 프로그래밍 >> C#

C# FluentValidation 완벽 가이드: 유창한 유효성 검사의 개념과 사용법

FluentValidation은 .NET 애플리케이션에서 강력한 형식(Strongly-Typed) 기반의 유효성 검사 규칙을 손쉽게 작성할 수 있도록 도와주는 오픈소스 라이브러리입니다. 유창한 인터페이스(Fluent Interface) 스타일과 람다 식(Lambda Expression)을 활용해 규칙을 선언형으로 구성할 수 있으며, 이를 통해 도메인 코드를 깔끔하게 유지하고 응집도를 높일 수 있습니다. 또한 여기저기 흩어지기 쉬운 유효성 검사 로직을 한 곳에서 체계적으로 관리할 수 있다는 점이 큰 장점입니다.

FluentValidation 패키지 설치

FluentValidation을 사용하려면 먼저 아래 NuGet 패키지를 프로젝트에 설치해야 합니다. Visual Studio의 NuGet 패키지 관리자 또는 .NET CLI를 통해 설치할 수 있습니다.

<PackageReference Include="FluentValidation" Version="9.2.2" />

예제 1: Person 모델 유효성 검사

아래 예제는 이름(FirstName), 성(LastName), 계좌 잔액(AccountBalance), 생년월일(DateOfBirth)을 가진 PersonModel 객체의 유효성을 검사하는 전체 과정을 보여줍니다. AbstractValidator<T>를 상속받는 PersonValidator 클래스에서 각 속성에 대한 검증 규칙을 정의합니다.

static class Program {
    static void Main(string[] args) {
        List<string> errors = new List<string>();

        PersonModel person = new PersonModel();
        person.FirstName = "";
        person.LastName = "S";
        person.AccountBalance = 100;
        person.DateOfBirth = DateTime.Now.Date;

        PersonValidator validator = new PersonValidator();
        ValidationResult results = validator.Validate(person);

        if (results.IsValid == false) {
            foreach (ValidationFailure failure in results.Errors) {
                errors.Add(failure.ErrorMessage);
            }
        }
        foreach (var item in errors) {
            Console.WriteLine(item);
        }
        Console.ReadLine();
    }
}

public class PersonModel {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal AccountBalance { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public class PersonValidator : AbstractValidator<PersonModel> {
    public PersonValidator() {
        RuleFor(p => p.FirstName)
        .Cascade(CascadeMode.StopOnFirstFailure)
        .NotEmpty().WithMessage("{PropertyName} is Empty")
        .Length(2, 50).WithMessage("Length ({TotalLength}) of {PropertyName} Invalid")
        .Must(BeAValidName).WithMessage("{PropertyName} Contains Invalid Characters");

        RuleFor(p => p.LastName)
        .Cascade(CascadeMode.StopOnFirstFailure)
        .NotEmpty().WithMessage("{PropertyName} is Empty")
        .Length(2, 50).WithMessage("Length ({TotalLength}) of {PropertyName} Invalid")
        .Must(BeAValidName).WithMessage("{PropertyName} Contains Invalid Characters");
    }

    protected bool BeAValidName(string name) {
        name = name.Replace(" ", "");
        name = name.Replace("-", "");
        return name.All(Char.IsLetter);
    }
}

코드 설명

  • RuleFor: 검사할 대상 속성을 지정하고, 해당 속성에 적용할 규칙들을 연결합니다.
  • Cascade(CascadeMode.StopOnFirstFailure): 한 속성에서 첫 번째 오류가 발생하면 나머지 규칙 검사를 중단해 불필요한 검증을 줄입니다.
  • NotEmpty / Length / Must: 각각 빈 값 여부, 문자열 길이 범위, 사용자 지정 조건을 검사합니다. BeAValidName처럼 직접 만든 메서드도 Must로 연결해 사용할 수 있습니다.
  • WithMessage: 검증 실패 시 출력할 메시지를 지정합니다. {PropertyName}, {TotalLength} 같은 자리 표시자(Placeholder)를 활용하면 동적인 메시지 작성이 가능합니다.
  • Validate: validator.Validate(person) 호출 결과로 ValidationResult가 반환되며, IsValid 속성으로 성공 여부를 확인하고 Errors 컬렉션에서 실패 상세 정보를 얻을 수 있습니다.

실행 결과

FirstName이 비어 있고, LastName의 길이가 최소 2자 미만이므로 콘솔에 다음과 같은 오류 메시지가 출력됩니다.

First Name is Empty
Length (1) of Last Name Invalid