التحقق من الخيارات والخيارات المسمّاة
تحقّقوا من صحة الخيارات عند بدء التشغيل باستخدام DataAnnotations أو FluentValidation، واستخدموا الخيارات المسمّاة لنسخ متعددة.
التحقق من الخيارات والخيارات المسمّاة درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في 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) دالة lambda للقواعد التي لا يمكن التعبير عنها باستخدام السمات، مثل القيود بين الخصائص.
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>();الخيارات المسماة — المفهوم
تتيح لك الخيارات المسماة تسجيل إعدادات متعددة من نوع الخيارات نفسه. ومن حالات الاستخدام الشائعة: عدة عملاء 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 البرمجية
تُعد OptionsBuilder<T>، التي تُعاد من AddOptions<T>()، واجهة برمجية أسلوبية تربط جميع خطوات التسجيل والربط والتحقق بطريقة واضحة.
// 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): دالة lambda مضمّنة للقواعد بين الخصائصIValidateOptions<T>: تحقق برمجي كامل مع عدة أخطاء- الخيارات المسماة:
Configure<T>(name, ...)معIOptionsMonitor<T>.Get(name) OptionsBuilder<T>: واجهة برمجية أسلوبية لربط جميع خطوات التسجيل
الأسئلة الشائعة
هل درس «التحقق من الخيارات والخيارات المسمّاة» مجاني؟
نعم — نص درس «التحقق من الخيارات والخيارات المسمّاة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «التحقق من الخيارات والخيارات المسمّاة»؟
تحقّقوا من صحة الخيارات عند بدء التشغيل باستخدام DataAnnotations أو FluentValidation، واستخدموا الخيارات المسمّاة لنسخ متعددة. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «التحقق من الخيارات والخيارات المسمّاة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- مصادر الإعداد وموفّروه
- الخيارات محدّدة الأنواع باستخدام IOptions
- التحقق من الخيارات والخيارات المسمّاة
- إدارة الأسرار