0Pricing
C# Academy · 강의

옵션 유효성 검사와 명명된 옵션

DataAnnotations 또는 FluentValidation으로 시작 시 옵션을 검증하고 여러 인스턴스에는 명명된 옵션을 사용합니다.

옵션 유효성 검사와 명명된 옵션은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

옵션의 유효성을 검사하는 이유

구성이 누락되거나 잘못된 형식이면 추적하기 어려운 실행 중 오류가 발생합니다. 시작 시 옵션의 유효성을 검사하면 조용히 발생하는 구성 버그가 설명이 명확한 예외로 드러나므로 어떤 요청도 처리되기 전에 문제를 확인할 수 있습니다.

ValidateOnStart

ValidateOnStart()는 처음 사용할 때 느슨하게 유효성을 검사하지 않고 앱이 시작되는 즉시 유효성을 검사합니다. 따라서 잘못 구성된 배포가 몇 시간 후가 아니라 즉시 실패합니다.

builder.Services
    .AddOptions<DatabaseOptions>()
    .BindConfiguration("Database")
    .ValidateDataAnnotations()
    .ValidateOnStart(); // throw OptionsValidationException on startup

// Without ValidateOnStart:
// - Validation only runs on first IOptions<T>.Value access
// - A rarely-used service could run for hours before failing

// With ValidateOnStart:
// - App fails at Host.Run() if config is invalid
// - Health checks and probes never report healthy for bad config

DataAnnotations 유효성 검사

옵션 클래스에서 표준 System.ComponentModel.DataAnnotations 특성을 사용합니다. 특성은 ValidateDataAnnotations()가 자동으로 평가합니다.

using System.ComponentModel.DataAnnotations;

public class EmailOptions
{
    [Required(ErrorMessage = "SMTP host is required")]
    [MinLength(3)]
    public string SmtpHost { get; set; } = string.Empty;

    [Range(1, 65535, ErrorMessage = "Port must be 1-65535")]
    public int SmtpPort { get; set; } = 587;

    [Required]
    [EmailAddress(ErrorMessage = "Invalid sender address")]
    public string SenderAddress { get; set; } = string.Empty;

    [Range(1, 30)]
    public int TimeoutSeconds { get; set; } = 10;
}

builder.Services
    .AddOptions<EmailOptions>()
    .BindConfiguration("Email")
    .ValidateDataAnnotations()
    .ValidateOnStart();

사용자 지정 유효성 검사 대리자

Validate(Func<T, bool>, string) 오버로드는 특성으로 표현할 수 없는 규칙, 예를 들어 속성 간 제약 조건을 위한 람다를 추가합니다.

builder.Services
    .AddOptions<ConnectionPoolOptions>()
    .BindConfiguration("ConnectionPool")
    .ValidateDataAnnotations()
    .Validate(
        opts => opts.MaxSize >= opts.MinSize,
        "MaxSize must be greater than or equal to MinSize")
    .Validate(
        opts => opts.ConnectionTimeoutMs > 0,
        "ConnectionTimeoutMs must be positive")
    .ValidateOnStart();

public class ConnectionPoolOptions
{
    [Range(1, 100)] public int MinSize { get; set; } = 2;
    [Range(1, 500)] public int MaxSize { get; set; } = 20;
    public int ConnectionTimeoutMs { get; set; } = 5000;
}

복잡한 규칙을 위한 IValidateOptions

여러 오류 메시지가 필요한 복잡한 논리에는 IValidateOptions<T>를 구현합니다. 이 구현은 옵션 인스턴스를 받아 자세한 실패 메시지가 포함된 결과를 반환합니다.

public class PaymentOptionsValidator : IValidateOptions<PaymentOptions>
{
    public ValidateOptionsResult Validate(string? name, PaymentOptions opts)
    {
        var failures = new List<string>();

        if (opts.Provider == "Stripe" && string.IsNullOrWhiteSpace(opts.StripeSecretKey))
            failures.Add("StripeSecretKey is required when Provider is Stripe");

        if (opts.Provider == "PayPal" && string.IsNullOrWhiteSpace(opts.PayPalClientId))
            failures.Add("PayPalClientId is required when Provider is PayPal");

        if (opts.RetryCount < 0 || opts.RetryCount > 5)
            failures.Add("RetryCount must be between 0 and 5");

        return failures.Count == 0
            ? ValidateOptionsResult.Success
            : ValidateOptionsResult.Fail(failures);
    }
}

builder.Services.AddSingleton<IValidateOptions<PaymentOptions>, PaymentOptionsValidator>();

이름이 지정된 옵션 — 개념

이름이 지정된 옵션을 사용하면 동일한 옵션 형식으로 여러 구성을 등록할 수 있습니다. 일반적인 사용 사례는 기본 URL과 시간 초과가 서로 다른 여러 외부 HTTP 클라이언트를 구성하는 것입니다.

// appsettings.json:
{
  "HttpClients": {
    "Orders": {
      "BaseUrl": "https://orders-service",
      "TimeoutSeconds": 30
    },
    "Inventory": {
      "BaseUrl": "https://inventory-service",
      "TimeoutSeconds": 10
    }
  }
}

public class HttpClientOptions
{
    public string BaseUrl { get; set; } = string.Empty;
    public int TimeoutSeconds { get; set; } = 30;
}

이름이 지정된 옵션 등록

Configure<T>의 첫 번째 인수로 이름 문자열을 전달합니다. IOptionsMonitor<T>.Get(name)을 사용하여 특정 인스턴스를 확인합니다.

// Register:
builder.Services.Configure<HttpClientOptions>("Orders",
    builder.Configuration.GetSection("HttpClients:Orders"));
builder.Services.Configure<HttpClientOptions>("Inventory",
    builder.Configuration.GetSection("HttpClients:Inventory"));

// Consume:
public class ApiGateway
{
    private readonly HttpClientOptions _orders;
    private readonly HttpClientOptions _inventory;

    public ApiGateway(IOptionsMonitor<HttpClientOptions> monitor)
    {
        _orders    = monitor.Get("Orders");
        _inventory = monitor.Get("Inventory");
    }

    // IOptions<T>.Value always returns the unnamed (default) instance
    // IOptionsMonitor<T>.Get(name) returns the named instance
}

유효성 검사를 포함한 이름이 지정된 옵션

이름이 지정된 각 등록에 대해 AddOptions<T>(name)을 호출하여 이름이 지정된 옵션의 유효성을 개별적으로 검사합니다.

foreach (var clientName in new[] { "Orders", "Inventory", "Auth" })
{
    builder.Services
        .AddOptions<HttpClientOptions>(clientName)
        .BindConfiguration($"HttpClients:{clientName}")
        .ValidateDataAnnotations()
        .Validate(
            opts => Uri.IsWellFormedUriString(opts.BaseUrl, UriKind.Absolute),
            $"HttpClients:{clientName}:BaseUrl must be a valid absolute URI")
        .ValidateOnStart();
}

// If any named instance fails, the app refuses to start

OptionsBuilder API

OptionsBuilder<T>(AddOptions<T>()가 반환)는 등록, 바인딩, 유효성 검사 단계를 모두 깔끔하게 연결하는 유창한 API입니다.

// Full OptionsBuilder chain:
builder.Services
    .AddOptions<DatabaseOptions>()        // create builder
    .BindConfiguration("Database")         // bind JSON section
    .Configure(opts =>                     // manual override
    {
        if (builder.Environment.IsDevelopment())
            opts.EnableDetailedErrors = true;
    })
    .PostConfigure(opts =>                 // runs after all Configure
    {
        opts.ConnectionString ??= "default-fallback";
    })
    .ValidateDataAnnotations()             // attribute rules
    .Validate(o => o.MaxPoolSize > 0,
              "MaxPoolSize must be positive")
    .ValidateOnStart();                    // eager validation

실전: 재시도 정책 옵션

필드 간 유효성 검사와 서비스별 이름이 지정된 정책을 포함한 완전한 재시도 옵션 설정입니다.

public class RetryOptions
{
    [Range(0, 10)] public int MaxAttempts { get; set; } = 3;
    [Range(100, 60000)] public int BaseDelayMs { get; set; } = 500;
    public bool UseExponentialBackoff { get; set; } = true;
    [Range(1, 120000)] public int MaxDelayMs { get; set; } = 30000;
}

foreach (var policy in new[] { "Database", "HttpClient", "MessageBus" })
{
    builder.Services
        .AddOptions<RetryOptions>(policy)
        .BindConfiguration($"RetryPolicies:{policy}")
        .Validate(o => !o.UseExponentialBackoff || o.MaxDelayMs > o.BaseDelayMs,
                  "MaxDelayMs must exceed BaseDelayMs when using exponential backoff")
        .ValidateOnStart();
}

빠른 확인

옵션을 등록할 때 ValidateOnStart()를 호출하면 어떤 이점이 있습니까?

복습: 옵션 유효성 검사 및 이름이 지정된 옵션

핵심 내용:

  • ValidateOnStart(): 처음 사용할 때가 아니라 시작 시 실패합니다
  • DataAnnotations: [Required], [Range] 등과 ValidateDataAnnotations()를 사용합니다
  • Validate(Func, message): 속성 간 규칙을 위한 인라인 람다입니다
  • IValidateOptions<T>: 여러 오류를 지원하는 전체 프로그램 기반 유효성 검사입니다
  • 이름이 지정된 옵션: Configure<T>(name, ...)과 IOptionsMonitor<T>.Get(name)을 사용합니다
  • OptionsBuilder<T>: 모든 등록 단계를 연결하는 유창한 API입니다

자주 묻는 질문

“옵션 유효성 검사와 명명된 옵션” 강의는 무료인가요?

네 — “옵션 유효성 검사와 명명된 옵션” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“옵션 유효성 검사와 명명된 옵션”에서 뭘 배우나요?

DataAnnotations 또는 FluentValidation으로 시작 시 옵션을 검증하고 여러 인스턴스에는 명명된 옵션을 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“옵션 유효성 검사와 명명된 옵션” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 구성 소스와 공급자
  2. IOptions를 사용한 강력한 형식의 옵션
  3. 옵션 유효성 검사와 명명된 옵션
  4. 보안 정보 관리
← C# Academy(으)로 돌아가기