مدیریت هوشمند تنظیمات در NET 11.: آشنایی با ConfigurationIgnoreAttribute
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۳/۲۰ ۰۸:۰۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
Microsoft.Extensions.Configuration سالهاست که وظیفه نگاشت (Binding) فایلهای تنظیمات (مانند appsettings.json) را به کلاسهای گزینهها (Options Classes) بر عهده دارد. با این حال، تا پیش از انتشار .NET 11، یک خلاء ملموس در این سیستم وجود داشت: عدم وجود یک راهکار رسمی و استاندارد برای نادیده گرفتن یک Property خاص در فرآیند Bind شدن.ConfigurationKeyNameAttribute را برای تغییر نام کلیدهای نگاشت معرفی کرد، اما امکان مسدود کردن کامل فرآیند Binding برای یک ویژگی مشخص وجود نداشت. خوشبختانه در .NET 11، با معرفی ویژگی جدید ConfigurationIgnoreAttribute، این شکاف بهطور کامل و به شکلی بومی برطرف شده است. در این مقاله، به بررسی ریشهای این چالش، راهکارهای موقت گذشته، و نحوه پیادهسازی این قابلیت جدید میپردازیم.public class CsvIngestionOptions
{
// این ویژگی حاصل پردازش ثانویه است و نباید مستقیماً از فایل تنظیمات خوانده شود
public CsvFormatOptions DefaultFormat { get; set; }
// بخش خامی که از فایل تنظیمات خوانده شده و خودمان آن را پردازش میکنیم
public IConfigurationSection? DefaultFormatSection { get; set; }
internal void OnConfigurationLoaded()
{
DefaultFormat = new CsvFormatOptions();
DefaultFormatSection?.Bind(DefaultFormat);
DefaultFormat.EnsureEncodingDefined();
}
}DefaultFormat قرار است پس از بارگذاری اولیه تنظیمات، مقداردهی و پردازش شود. اما از آنجایی که این ویژگی دارای دسترسیهای عمومی (public get; set;) است، سیستم Configuration مکانیزم .NET به صورت خودکار و کورکورانه تلاش میکند تا در صورت وجود کلیدی همنام در فایل JSON، آن را مقداردهی کند. این رفتار میتواند منجر به بازنویسی (Overwrite) ناخواسته دادهها، بروز رفتارهای پیشبینینشده یا کاهش کارایی برنامه شود.ConfigurationKeyNameAttribute و ارجاع آن به یک کلید ساختگی و نامعتبر بود:// یک راهکار غیر استاندارد و آسیبپذیر
[ConfigurationKeyName("__ignored_" + nameof(DefaultFormat))]
public CsvFormatOptions DefaultFormat { get; set; }private یا internal بود که آن هم انعطافپذیری کد را برای دسترسی در سایر بخشهای برنامه محدود میکرد.sealed) را در فضای نام Microsoft.Extensions.Configuration معرفی کرده است:namespace Microsoft.Extensions.Configuration;
[AttributeUsage(AttributeTargets.Property)]
public sealed class ConfigurationIgnoreAttribute : Attribute { }using Microsoft.Extensions.Configuration;
public class CsvIngestionOptions
{
[ConfigurationIgnore]
public CsvFormatOptions DefaultFormat { get; set; }
[ConfigurationKeyName(nameof(DefaultFormat))]
public IConfigurationSection? DefaultFormatSection { get; set; }
internal void OnConfigurationLoaded()
{
DefaultFormat = new CsvFormatOptions();
DefaultFormatSection?.Bind(DefaultFormat);
DefaultFormat.EnsureEncodingDefined();
}
}public class FeatureFlags
{
// مقداری که مستقیماً از appsettings.json خوانده میشود
public string RawFlags { get; set; } = string.Empty;
// خروجی پردازش شده که باید از دید فرآیند Binding پنهان بماند
[ConfigurationIgnore]
public IReadOnlyDictionary<string, bool> ParsedFlags { get; set; }
= new Dictionary<string, bool>();
}appsettings.json با ساختارهای سریالسازی JSON، گمان میکنند که استفاده از اتریبیوت [JsonIgnore] متعلق به اکوسیستم System.Text.Json میتواند این مشکل را حل کند.نکته کلیدی علمی: سیستم پیکربندی NET (Microsoft.Extensions.Configuration). یک لایه انتزاعی (Abstraction) مستقل است و از هسته سریالسازی JSON مجزا عمل میکند. این سیستم دادهها را از منابع مختلفی مانند کدهای دستوری (CLI Arguments)، متغیرهای محیطی (Environment Variables)، دیتابیسها و فایلهای XML/JSON جمعآوری کرده و به یک ساختار کلید-مقدار (Key-Value) تخت تبدیل میکند. بنابراین، Binder داخلی تنظیمات هیچ شناختی از اتریبیوتهای اختصاصیSystem.Text.JsonیاNewtonsoft.Jsonندارد و آنها را کاملاً نادیده میگیرد.
[ConfigurationIgnore] را شناسایی کرده و هیچ کدی برای نگاشت آنها تولید نمیکنند. این امر باعث میشود که برنامه شما نه تنها از نظر طراحی تمیزتر باشد، بلکه از نظر مصرف حافظه و سرعت اجرا (Performance) در زمان بالا آمدن اپلیکیشن (Startup) نیز بهینهتر عمل کند.ConfigurationIgnoreAttribute در .NET 11، شاید در نگاه اول یک تغییر کوچک به نظر برسد، اما یک نقص طراحی قدیمی را برطرف کرده و به توسعهدهندگان اجازه میدهد کدهایی تمیزتر، امنتر و با قابلیت نگهداری بالاتر بنویسند. با این قابلیت، جداسازی میان «دادههای خام ورودی تنظیمات» و «وضعیتهای محاسباتی درون برنامه» به بهترین شکل ممکن پیادهسازی میشود. اگر در حال مهاجرت یا شروع پروژهای با .NET 11 هستید، پیشنهاد میشود تمامی راهکارهای موقت قبلی را با این اتریبیوت بومی جایگزین کنید.