C# Academy · บทเรียน

Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions

ผูกส่วนการกำหนดค่าเข้ากับคลาส POCO ด้วย IOptions , IOptionsSnapshot และ IOptionsMonitor

บทเรียน 2 จาก 412 ขั้นตอน

Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงใช้อ็อปชันแบบมีชนิดข้อมูลชัดเจน

การอ่านการกำหนดค่าด้วย IConfiguration["Key"] จะได้สตริงที่ไม่มีชนิดข้อมูล รูปแบบอ็อปชันจะจับคู่ส่วนการกำหนดค่ากับคลาส C# ทำให้มีความปลอดภัยตั้งแต่เวลาคอมไพล์ รองรับ IntelliSense และรองรับการตรวจสอบความถูกต้อง

การกำหนดคลาสอ็อปชัน

สร้างคลาส POCO ธรรมดาที่มีชื่อคุณสมบัติตรงกับคีย์ JSON ตามธรรมเนียมแล้ว ให้เพิ่มค่าคงที่แบบ static ชื่อ SectionName เพื่อระบุส่วนการกำหนดค่า

// Configuration class
public class JwtOptions
{
    public const string SectionName = "Jwt";

    public string SecretKey { get; set; } = string.Empty;
    public string Issuer    { get; set; } = string.Empty;
    public string Audience  { get; set; } = string.Empty;
    public int    ExpiryMinutes { get; set; } = 60;
}

// appsettings.json:
{
  "Jwt": {
    "SecretKey": "my-very-secret-key",
    "Issuer": "https://myapp.com",
    "Audience": "https://myapp.com/api",
    "ExpiryMinutes": 120
  }
}

การลงทะเบียนอ็อปชัน

เรียกใช้ Configure<T> เพื่อผูกส่วนการกำหนดค่าเข้ากับคลาสอ็อปชัน การดำเนินการนี้จะลงทะเบียน IOptions<T> IOptionsSnapshot<T> และ IOptionsMonitor<T> ใน DI

// Registration
builder.Services.Configure<JwtOptions>(
    builder.Configuration.GetSection(JwtOptions.SectionName));

// Alternative shorthand:
builder.Services
    .AddOptions<JwtOptions>()
    .BindConfiguration(JwtOptions.SectionName);

// Consuming via IOptions<T>:
public class TokenService
{
    private readonly JwtOptions _opts;

    public TokenService(IOptions<JwtOptions> opts)
        => _opts = opts.Value;

    public string CreateToken()
        => $"Issuer={_opts.Issuer}, Exp={_opts.ExpiryMinutes}m";
}

IOptions เทียบกับ IOptionsSnapshot เทียบกับ IOptionsMonitor

มีสามรูปแบบที่มีอายุการใช้งานและพฤติกรรมการโหลดใหม่แตกต่างกัน โปรดเลือกแบบที่เหมาะกับกรณีใช้งานของคุณ

// IOptions<T> — Singleton, reads config ONCE at startup
public class ApiClient(IOptions<ApiOptions> opts)
{
    private readonly ApiOptions _opts = opts.Value; // never changes
}

// IOptionsSnapshot<T> — Scoped, reloads per request
public class ReportService(IOptionsSnapshot<ReportOptions> opts)
{
    private readonly ReportOptions _opts = opts.Value; // fresh per request
}

// IOptionsMonitor<T> — Singleton, live updates + change notifications
public class FeatureService(IOptionsMonitor<FeatureFlags> monitor)
{
    public bool IsEnabled(string feature)
        => monitor.CurrentValue.EnabledFeatures.Contains(feature);
}

การตรวจสอบอ็อปชันด้วยแอตทริบิวต์

ตกแต่งคุณสมบัติของอ็อปชันด้วยแอตทริบิวต์ System.ComponentModel.DataAnnotations และเรียกใช้ ValidateDataAnnotations() เพื่อตรวจพบการกำหนดค่าที่ไม่ถูกต้องทันทีเมื่อเริ่มต้น

using System.ComponentModel.DataAnnotations;

public class SmtpOptions
{
    [Required]
    public string Host { get; set; } = string.Empty;

    [Range(1, 65535)]
    public int Port { get; set; } = 587;

    [Required, EmailAddress]
    public string FromAddress { get; set; } = string.Empty;
}

// Register with validation:
builder.Services
    .AddOptions<SmtpOptions>()
    .BindConfiguration("Smtp")
    .ValidateDataAnnotations()
    .ValidateOnStart(); // fail at startup, not first use

การตรวจสอบแบบกำหนดเองด้วย IValidateOptions

สำหรับกฎที่ซับซ้อนซึ่งครอบคลุมหลายคุณสมบัติ ให้นำ IValidateOptions<T> ไปใช้งานเพื่อควบคุมตรรกะการตรวจสอบทั้งหมดด้วยโค้ด

public class JwtOptionsValidator : IValidateOptions<JwtOptions>
{
    public ValidateOptionsResult Validate(string? name, JwtOptions opts)
    {
        var errors = new List<string>();

        if (string.IsNullOrWhiteSpace(opts.SecretKey))
            errors.Add("SecretKey must not be empty");

        if (opts.SecretKey.Length < 32)
            errors.Add("SecretKey must be at least 32 characters");

        if (opts.ExpiryMinutes <= 0)
            errors.Add("ExpiryMinutes must be positive");

        return errors.Any()
            ? ValidateOptionsResult.Fail(errors)
            : ValidateOptionsResult.Success;
    }
}

builder.Services.AddSingleton<IValidateOptions<JwtOptions>, JwtOptionsValidator>();

Post-Configure

PostConfigure จะทำงานหลังจากการเรียกใช้ Configure ทั้งหมด และเปิดให้คุณเขียนทับหรือคำนวณค่าได้ เหมาะสำหรับคุณสมบัติที่คำนวณขึ้นหรือการปรับแต่งตามสภาพแวดล้อม

builder.Services.Configure<CacheOptions>(
    builder.Configuration.GetSection("Cache"));

// Override in test environment:
builder.Services.PostConfigure<CacheOptions>(opts =>
{
    if (builder.Environment.IsEnvironment("Testing"))
    {
        opts.AbsoluteExpirationMinutes = 1; // very short in tests
        opts.UseDistributedCache = false;   // use in-memory cache
    }
});

// PostConfigure always runs LAST, even after AddOptions validators

อ็อปชันแบบตั้งชื่อ

เมื่อจำเป็นต้องมีอ็อปชันชนิดเดียวกันหลายอินสแตนซ์ เช่น เซิร์ฟเวอร์ SMTP สองตัว ให้ใช้อ็อปชันแบบตั้งชื่อเพื่อแยกความแตกต่างระหว่างอินสแตนซ์

// Register named options:
builder.Services.Configure<SmtpOptions>("Primary",
    builder.Configuration.GetSection("Smtp:Primary"));
builder.Services.Configure<SmtpOptions>("Backup",
    builder.Configuration.GetSection("Smtp:Backup"));

// Consume with IOptionsMonitor (supports named options):
public class EmailSender
{
    private readonly SmtpOptions _primary;
    private readonly SmtpOptions _backup;

    public EmailSender(IOptionsMonitor<SmtpOptions> monitor)
    {
        _primary = monitor.Get("Primary");
        _backup  = monitor.Get("Backup");
    }
}

รูปแบบย่อของ BindConfiguration

สายการเรียกใช้ AddOptions().BindConfiguration() เป็นแนวทางแบบต่อเนื่องสมัยใหม่สำหรับลงทะเบียน ผูก ตรวจสอบ และหยุดทำงานทันทีทั้งหมดในนิพจน์เดียว

// Full registration chain:
builder.Services
    .AddOptions<DatabaseOptions>()
    .BindConfiguration("Database")          // bind section
    .ValidateDataAnnotations()               // attribute validation
    .Validate(opts =>                        // custom rule
        opts.MaxPoolSize >= opts.MinPoolSize,
        "MaxPoolSize must be >= MinPoolSize")
    .ValidateOnStart();                      // fail at startup

// Shorthand for simple cases:
builder.Services.AddOptions<AppOptions>()
    .BindConfiguration(AppOptions.SectionName)
    .ValidateOnStart();

กรณีใช้งานจริง: อ็อปชันของแฟล็กฟีเจอร์

การตั้งค่าอ็อปชันของแฟล็กฟีเจอร์แบบครบถ้วนพร้อมรองรับการโหลดใหม่ ทำให้สามารถเปลี่ยนสวิตช์เปิดปิดใน appsettings ได้โดยไม่ต้องนำระบบไปใช้งานใหม่

public class FeatureFlags
{
    public bool EnableNewCheckout  { get; set; }
    public bool EnableAISearch     { get; set; }
    public bool EnableBetaDashboard { get; set; }
}

// appsettings.json:
// { "FeatureFlags": { "EnableNewCheckout": true, ... } }

builder.Services
    .AddOptions<FeatureFlags>()
    .BindConfiguration("FeatureFlags")
    .ValidateOnStart();

// In a controller or service:
public class CheckoutController : ControllerBase
{
    private readonly FeatureFlags _flags;

    public CheckoutController(IOptionsMonitor<FeatureFlags> m)
        => _flags = m.CurrentValue;

    [HttpGet("/checkout")]
    public IActionResult Index() =>
        _flags.EnableNewCheckout
            ? Ok("new checkout")
            : Ok("legacy checkout");
}

ตรวจสอบความเข้าใจ

ควรใช้ IOptions รูปแบบใดในบริการแบบ Singleton ที่ต้องสะท้อนการเปลี่ยนแปลงของการกำหนดค่าแบบทันที

สรุปทบทวน: อ็อปชันแบบมีชนิดข้อมูลชัดเจนด้วย IOptions

ประเด็นสำคัญ:

  • รูปแบบอ็อปชันจะผูกส่วนการกำหนดค่ากับ POCO ผ่าน Configure<T> หรือ AddOptions<T>().BindConfiguration()
  • IOptions<T>: เป็น Singleton และอ่านค่าเพียงครั้งเดียวเมื่อเริ่มต้น
  • IOptionsSnapshot<T>: มีขอบเขตและโหลดใหม่ทุกคำขอ — ห้ามฉีดเข้าไปใน Singleton
  • IOptionsMonitor<T>: ใช้กับ Singleton ได้อย่างปลอดภัย โดยมี CurrentValue แบบทันทีและ OnChange
  • ตรวจสอบด้วย DataAnnotations + ValidateDataAnnotations() + ValidateOnStart()
  • ใช้อ็อปชันแบบตั้งชื่อเมื่อมีอินสแตนซ์ชนิดเดียวกันหลายรายการ
เริ่มต้นได้ฟรี

เรียนรู้ C# ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
93
บทเรียน
346

คำถามที่พบบ่อย

บทเรียน “Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions”

ผูกส่วนการกำหนดค่าเข้ากับคลาส POCO ด้วย IOptions , IOptionsSnapshot และ IOptionsMonitor คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แหล่งและผู้ให้บริการการกำหนดค่า
  2. Options แบบระบุชนิดอย่างเคร่งครัดด้วย IOptions
  3. การตรวจสอบ Options และ Named Options
  4. การจัดการข้อมูลลับ
← กลับไปที่ C# Academy