استفاده از IOptionsSnapshot برای خواندن دادههای بهروزشده ⚙️📄
IOptionsSnapshot<TOptions>🧪:
🔹️تنظیمات (Options) در هر درخواست یک بار محاسبه میشوند و برای مدت زمان همان درخواست کش میشوند.
🔹️چون یک سرویس Scoped است و در هر درخواست دوباره محاسبه میشود، ممکن است باعث هزینهٔ کارایی شود.
🔹️زمانی تغییرات پیکربندی را پس از شروع برنامه میخواند که Provider مربوطه از بارگذاری مجدد پشتیبانی کند.
تفاوت IOptionsMonitor با IOptionsSnapshot🖇:
🔸️ءIOptionsMonitor یک Singleton است و همیشه مقدار لحظهای تنظیمات را ارائه میدهد؛ مناسب برای سرویسهای Singleton.
🔸️ءIOptionsSnapshot یک Scoped است و هنگام ایجاد شدن، یک Snapshot از تنظیمات میگیرد؛ مناسب برای سرویسهای Transient و Scoped.
نمونهٔ استفاده از <IOptionsSnapshot<TOptions🧪
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
ثبت MyOptions در DI 🧩
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
در این حالت، تغییرات فایل JSON پس از شروع برنامه خوانده میشوند.
IOptionsMonitor 🛰
ثبت MyOptions در سرویسها (مانند قبل)
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
نمونهٔ استفاده از <IOptionsMonitor<TOptions 📡
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
در این حالت نیز، تغییرات JSON بعد از شروع برنامه خوانده میشوند.
استفاده از ConfigurationKeyName برای تعیین کلید سفارشی 🔑✨
بهطور پیشفرض، نام پراپرتی کلاس Options برابر با نام کلید در پیکربندی است.
اگر بین نام پراپرتی و نام کلید تفاوت وجود دارد، میتوان از ConfigurationKeyName استفاده کرد.
مواقع استفاده:
• زمانی که نام کلید در پیکربندی یک شناسهٔ معتبر #C نیست.
• یا زمانی که میخواهید نام متفاوتی در کد داشته باشید.
مثال 🎯
public class PositionOptionsWithConfigurationKeyName
{
public const string Position = "Position";
[ConfigurationKeyName("position-title")]
public string Title { get; set; } = string.Empty;
[ConfigurationKeyName("position-name")]
public string Name { get; set; } = string.Empty;
}
فایل appsettings.json
{
"Position": {
"position-title": "Editor",
"position-name": "Joe Smith"
}
}
در نتیجه،
Title ← مقدار position-title
Name ← مقدار position-name
پشتیبانی از Named Options با استفاده از IConfigureNamedOptions 🎯⚙️
🔹️ءNamed Options چه هستند؟
ءNamed Options زمانی مفید هستند که:
• چند بخش متفاوت از configuration نیاز دارند به یک کلاس مشترک Bind شوند.
• نامگذاریها Case-Sensitive هستند.
• بتوانیم چند نسخهٔ متفاوت از یک Options را با Names مختلف مدیریت کنیم.
مثال فایل appsettings.json 📄
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}در این مثال، دو بخش داریم:
TopItem:Month
TopItem:Year
بهجای تعریف دو کلاس جداگانه، از یک کلاس مشترک استفاده میکنیم:
کلاس مشترک TopItemSettings 🧱
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}