عنوان:

‫راهنمای جامع مدیریت تنظیمات در دات‌نت کور: IConfiguration, IOptions


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۶/۱۶ ۱۰:۴۳
آدرس: www.dntips.ir
چرا مدیریت تنظیمات (Configuration) در دات‌نت کور حیاتی است؟

در دنیای توسعه نرم‌افزار، به ویژه در اکوسیستم دات‌نت کور (Microsoft .NET Core)، مدیریت تنظیمات یک فرآیند بنیادی و حیاتی است. تنظیمات (Configuration) شامل اطلاعاتی مانند رشته‌های اتصال به پایگاه داده، کلیدهای دسترسی به API، تنظیمات logging، و سایر داده‌های محیطی است که رفتار برنامه را تعیین می‌کنند. استفاده از یک شیوه درست و استاندارد برای مدیریت این اطلاعات، نه تنها به بهبود سازماندهی و امنیت کد کمک می‌کند، بلکه انعطاف‌پذیری و قابلیت نگهداری (Maintainability) آن را به شکل چشمگیری افزایش می‌دهد. دات‌نت کور ابزارهای قدرتمندی برای این منظور فراهم کرده که توسعه‌دهندگان را قادر می‌سازد تا به جای hard-coding اطلاعات حساس، آن‌ها را از منابع خارجی مانند فایل‌های JSON، متغیرهای محیطی یا Azure Key Vault بخوانند. این مقاله به بررسی عمیق سه الگوی اصلی در مدیریت تنظیمات یعنی IConfiguration، IOptions و دسترسی قوی‌تایپ (Strongly-Typed) می‌پردازد تا به شما در انتخاب بهترین رویکرد برای پروژه‌هایتان کمک کند.

بررسی عمیق الگوهای مدیریت تنظیمات در دات‌نت کور

1. رابط IConfiguration: دسترسی مستقیم به تنظیمات
IConfiguration رابطی است که دسترسی ساده و مستقیم به مقادیر کلید-مقدار (key-value) تنظیمات را فراهم می‌کند. این رابط به شما اجازه می‌دهد تا به تمامی اطلاعات پیکربندی برنامه، صرف‌نظر از منبع آن، دسترسی داشته باشید. این اطلاعات به صورت سلسله‌مراتبی و با استفاده از علامت دو نقطه (colon) برای جدا کردن بخش‌ها سازمان‌دهی شده‌اند. برای مثال، اگر در فایل appsettings.json خود چنین ساختاری داشته باشید:
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning"
    }
  },
  "MySettings": {
    "ApiKey": "abc-123",
    "MaxRetries": 3
  }
}
می‌توانید با تزریق (inject) IConfiguration به سرویس یا کنترلر خود و استفاده از سینتکس ایندکسر، به مقادیر آن دسترسی پیدا کنید.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

public class MyService
{
    private readonly IConfiguration _configuration;
    private readonly ILogger<MyService> _logger;

    public MyService(IConfiguration configuration, ILogger<MyService> logger)
    {
        _configuration = configuration;
        _logger = logger;
    }

    public void DoSomething()
    {
        string apiKey = _configuration["MySettings:ApiKey"];
        _logger.LogInformation($"API Key: {apiKey}");
    }
}
این رویکرد ساده و انعطاف‌پذیر است، اما دارای معایبی است:
  • ایمنی نوع (Type Safety) پایین: تمامی مقادیر به صورت رشته (string) خوانده می‌شوند و تبدیل نوع (type casting) دستی لازم است که می‌تواند منجر به خطاهای زمان اجرا (runtime errors) شود.
  • عدم به‌روزرسانی خودکار: IConfiguration به طور پیش‌فرض، تغییرات در فایل‌های تنظیمات را در زمان اجرا منعکس نمی‌کند.
  • وابستگی مستقیم: هر سرویسی که به IConfiguration وابسته است، به تمامی تنظیمات دسترسی دارد که این امر اصل تفکیک مسئولیت‌ها (Separation of Concerns) را نقض می‌کند.

2. الگوی Options: دسترسی قوی‌تایپ و مبتنی بر کلاس
الگوی Options راه حل ایده‌آل برای رفع محدودیت‌های IConfiguration است. این الگو، به جای دسترسی به مقادیر به صورت رشته، آن‌ها را به کلاس‌های Plain Old C# Object (POCO) با ساختار مشخص نگاشت (map) می‌کند. این رویکرد، ایمنی نوع (Type Safety) را تضمین کرده و کد را خواناتر و قابل نگهداری‌تر می‌سازد.
برای استفاده از این الگو، ابتدا یک کلاس POCO تعریف می‌کنید که ساختار داده‌های تنظیمات شما را منعکس می‌کند:
public class MySettings
{
    public const string SectionName = "MySettings";
    public string ApiKey { get; set; }
    public int MaxRetries { get; set; }
}
سپس، در متد ConfigureServices در فایل Program.cs یا Startup.cs، بخش مربوطه از تنظیمات را به کلاس MySettings متصل (bind) می‌کنید:
builder.Services.Configure<MySettings>(
    builder.Configuration.GetSection(MySettings.SectionName));
حالا می‌توانید با تزریق رابط <IOptions<MySettings در هر سرویسی که به آن نیاز دارید، به مقادیر قوی‌تایپ شده دسترسی پیدا کنید.
using Microsoft.Extensions.Options;

public class MyService
{
    private readonly MySettings _settings;

    public MyService(IOptions<MySettings> settings)
    {
        _settings = settings.Value;
    }

    public void DoSomething()
    {
        string apiKey = _settings.ApiKey;
        // استفاده از مقادیر
    }
}
استفاده از IOptions به کلاس شما اجازه می‌دهد تا فقط به بخشی از تنظیمات که به آن نیاز دارد دسترسی داشته باشد، که این امر وابستگی‌ها را کاهش داده و کد را تمیزتر می‌کند. اما IOptions مقادیر را فقط یک بار در زمان راه‌اندازی برنامه (application startup) می‌خواند و از تغییرات در حین اجرای برنامه پشتیبانی نمی‌کند.

3. قابلیت به‌روزرسانی خودکار تنظیمات: IOptionsSnapshot و IOptionsMonitor
برای سناریوهایی که نیاز به به‌روزرسانی تنظیمات در حین اجرای برنامه دارید، دات‌نت کور دو رابط پیشرفته‌تر را ارائه می‌دهد: <IOptionsSnapshot<T و <IOptionsMonitor<T.
  • <IOptionsSnapshot<T: این رابط، در هر درخواست وب (web request) یک "عکس لحظه‌ای" (snapshot) از تنظیمات را فراهم می‌کند. این بدان معناست که اگر فایل appsettings.json در حین اجرای برنامه تغییر کند، هر درخواست جدید، مقدار به‌روزرسانی شده را دریافت می‌کند. این رابط به طور خاص برای برنامه‌های وب مناسب است و به عنوان یک سرویس با عمر scoped ثبت می‌شود، بنابراین هر درخواست، نسخه‌ی مستقل و تازه‌ای از تنظیمات را دریافت می‌کند.
  • <IOptionsMonitor<T: این رابط، برای سناریوهایی مانند سرویس‌های طولانی‌مدت (long-running services) یا تسک‌های پس‌زمینه (background tasks) که به به‌روزرسانی بلادرنگ (real-time updates) نیاز دارند، طراحی شده است. IOptionsMonitor به عنوان یک سرویس تک‌گانه (singleton) عمل کرده و همیشه آخرین مقدار تنظیمات را از طریق ویژگی CurrentValue ارائه می‌دهد. علاوه بر این، IOptionsMonitor به شما اجازه می‌دهد تا به تغییرات تنظیمات مشترک شوید و اقداماتی را در پاسخ به آن‌ها انجام دهید.
using Microsoft.Extensions.Options;

public class BackgroundWorker
{
    private readonly IOptionsMonitor<MySettings> _settingsMonitor;

    public BackgroundWorker(IOptionsMonitor<MySettings> settingsMonitor)
    {
        _settingsMonitor = settingsMonitor;
        _settingsMonitor.OnChange((updatedSettings, name) =>
        {
            // این کد در زمان تغییر تنظیمات اجرا می‌شود
            Console.WriteLine($"Settings changed. New API Key: {updatedSettings.ApiKey}");
        });
    }

    public void DoWorkContinuously()
    {
        // دسترسی به آخرین مقدار در هر لحظه
        string currentApiKey = _settingsMonitor.CurrentValue.ApiKey;
        // استفاده از currentApiKey
    }
}

سوال: کدام یک از رابط‌های مدیریت تنظیمات در دات‌نت کور، برای برنامه‌های وب که نیاز دارند در هر درخواست (web request)، جدیدترین مقادیر پیکربندی را دریافت کنند، مناسب‌ترین گزینه است؟
  • IConfiguration
  • IOptions<T>
  • IOptionsSnapshot<T>
  • IOptionsMonitor<T>


نتیجه‌گیری

مدیریت موثر تنظیمات در دات‌نت کور فراتر از خواندن ساده‌ی داده‌ها از یک فایل است. با انتخاب صحیح میان IConfiguration، IOptions<T>، IOptionsSnapshot<T> و IOptionsMonitor<T>، توسعه‌دهندگان می‌توانند کدی ایمن‌تر، قابل نگهداری‌تر و انعطاف‌پذیرتر ایجاد کنند.
برای دسترسی‌های ساده و مستقیم، IConfiguration گزینه مناسبی است. با این حال، در اغلب موارد، الگوی Options و رابط‌های IOptions<T>، IOptionsSnapshot<T> و IOptionsMonitor<T> به دلیل ارائه دسترسی قوی‌تایپ و پشتیبانی از به‌روزرسانی‌های پویا، رویکرد بهتری محسوب می‌شوند. انتخاب هر یک از این رابط‌ها به نیازهای خاص برنامه شما، مانند نوع برنامه (سرویس طولانی‌مدت یا برنامه وب) و نیاز به به‌روزرسانی تنظیمات در زمان اجرا، بستگی دارد. با درک دقیق این ابزارها، می‌توانید به بهترین شکل از پتانسیل کامل فریم‌ورک دات‌نت کور بهره‌مند شوید.



پاسخ کوئیز
پاسخ صحیح گزینه ۳ (<IOptionsSnapshot<T) است.
  • IOptionsSnapshot به طور خاص برای سناریوهای وب طراحی شده و در هر درخواست یک کپی تازه از تنظیمات را ارائه می‌دهد، که این امر به اطمینان از دریافت جدیدترین مقادیر در هر درخواست کمک می‌کند. IOptionsMonitor نیز از به‌روزرسانی پشتیبانی می‌کند اما به عنوان یک سرویس تک‌گانه (singleton) عمل کرده و برای سرویس‌های طولانی‌مدت مناسب‌تر است.


مشاهده مطلب اصلی