محتويات الدورة

ASP.NET Core / المتوسط: البيانات والهوية والعمل غير المتزامن / الدرس 7

الإعدادات والخيارات وحدود الأسرار

اجعل أولوية موفّرات الإعدادات، والإعدادات ذات الأنواع المحددة، وتوقيت التحقق، وسلوك إعادة التحميل، وملكية الأسرار أمورا صريحة.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اشرح ترتيب موفّرات الإعدادات والمفاتيح الهرمية.
  • تحقق من صحة الخيارات ذات الأنواع المحددة عند الحد المقصود.
  • أبعد الإعدادات والأسرار عن السجلات العرضية والاعتماديات غير المقصودة في الاختبارات.

تجمع الإعدادات موفّراتها بترتيب محدد

تمثل الإعدادات تجريدا من مفاتيح وقيم، يُبنى من موفّرات مثل JSON أو متغيرات البيئة أو سطر الأوامر أو بيانات صريحة في الذاكرة. تستطيع الموفّرات المضافة لاحقا أن تستبدل قيم مفاتيح سابقة، وفقا لعقد كل موفّر. تسهّل القيم الافتراضية للمضيف الإعداد، لكنها قد تجعل الاختبارات تعتمد على حالة الجهاز إذا استُخدمت دون قصد. سجّل الموفّرات الفعلية والبيئة المستخدمة حتى يمكن إعادة إنتاج السلوك.

تستخدم المفاتيح الهرمية مسارا منطقيا، ويحوّل كل موفّر صياغة مصدره إلى ذلك المسار. تمثل الشرطتان السفليتان المتتاليتان في متغيرات البيئة عادة فواصل المسار، لكن هذا الدرس لا يقرأ بيئة العملية ولا يغيّرها. يستحق غياب المفتاح، ووجود قيمة فارغة، وعدد مكتوب بصيغة غير صالحة، وفشل الوصول إلى سر، تشخيصات مختلفة.

اختبر الأولوية بموفّرات ذاكرة اصطناعية

يضيف البرنامج الأول موفّرين في الذاكرة للمفتاح نفسه. تسود القيمة الثانية، فتكون النتيجة 6. يختبر ذلك أولوية الموفّرات دون قراءة ملفات appsettings في مستودع، أو متغيرات البيئة، أو أسرار المستخدم، أو خزنة خارجية. ينبغي أن ينشئ الاختبار فقط المصادر المتعلقة بالسلوك الذي يدعي التحقق منه.

لا تستنتج من استبدال قيمة نصية أن كل مكوّن سيعيد تحميل القيمة ذات النوع المحدد فورا. فقد تختلف مدد الحياة عند استهلاكها عبر الخيارات، أو الاحتفاظ بها في حقل لخدمة مفردة النسخة، أو تخزينها مؤقتا يدويا. إشعار الموفّر بحدوث تغيير واستجابة التطبيق لذلك التغيير جزآن منفصلان من عقد إعادة التحميل.

csharp التحقق من أولوية موفّرات معزولة
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;

using var configuration = new ConfigurationManager();
configuration.AddInMemoryCollection(new Dictionary<string, string?> { ["Reports:Limit"] = "4" });
configuration.AddInMemoryCollection(new Dictionary<string, string?> { ["Reports:Limit"] = "6" });
Console.WriteLine($"limit={configuration["Reports:Limit"]}");
الناتج المتوقع
limit=6

لا يشارك سوى موفّرين اصطناعيين؛ وتكون القيمة اللاحقة 6.

تحتاج الخيارات ذات الأنواع المحددة إلى توقيت تحقق صريح

تجمع آلية الخيارات إعدادات مترابطة وراء عقد ذي نوع محدد. تؤدي IOptions وIOptionsSnapshot وIOptionsMonitor أدوارا مختلفة في التخزين المؤقت والنطاق وملاحظة التغييرات. اختر الصيغة الموافقة لمدة حياة المستهلك؛ ولا تحقن لقطة خيارات ذات نطاق في خدمة مفردة النسخة لمجرد أنها تعرض الخاصية المطلوبة.

يمكن أن يعمل التحقق عند إنشاء قيمة الخيارات أو الوصول إليها، بينما ترتب ValidateOnStart التحقق أثناء بدء التشغيل عبر مسار المضيف. يثبت اختبار طرفية يقرأ IOptions.Value التحقق من القيمة عند الوصول، ولا يثبت تحقق بدء المضيف. اجعل القيود بين الحقول والحدود العددية صريحة، حتى لا يتحول خطأ في الإعداد إلى عمل غير محدود أو قيمة افتراضية غير آمنة.

اقرأ خيارات متحققا منها عبر حاوية الاعتماديات

يسجل البرنامج الثاني قيمة خيارات اصطناعية واحدة وقاعدة تحد حجم الصفحة، ثم يقرأها عبر حقن الاعتماديات. لو خرجت القيمة عن القاعدة، لنتج إخفاق التحقق من الخيارات الموثق عند الإنشاء أو الوصول. القيمة الصحيحة المعروضة، وهي 25، ليست حدا عاما لكل التطبيقات؛ إنها مثال محلي على تحويل متطلب من المجال إلى فحص.

لا تسجل كائن الخيارات كاملا إذا كان قد يحتوي على أسرار اتصال أو رموز اعتماد. سجّل فئة آمنة واسم المفتاح بدلا من محتوى الاعتماد. تعامل مع فشل التحقق عند البدء بوصفه رفضا واضحا لقبول العمل، لا مبررا للاستمرار بموارد لم يكتمل إعدادها.

csharp ملاحظة خيار اصطناعي متحقق منه
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

var services = new ServiceCollection();
services.AddOptions<ReportOptions>()
    .Configure(options => options.PageSize = 25)
    .Validate(options => options.PageSize is >= 1 and <= 100, "PageSize outside range");
using var provider = services.BuildServiceProvider();
int size = provider.GetRequiredService<IOptions<ReportOptions>>().Value.PageSize;
Console.WriteLine($"pageSize={size}");

internal sealed class ReportOptions { public int PageSize { get; set; } }
الناتج المتوقع
pageSize=25

تؤدي قراءة Value إلى إنشاء الخيارات المضبوطة والتحقق منها؛ وهذا ليس اختبارا لبدء المضيف.

تغييرات الإعدادات هي تغييرات في التطبيق

قد تغيّر الإعدادات القابلة لإعادة التحميل الحدود، أو المسارات إلى الاعتماديات، أو سلوك الميزات، أو الافتراضات الأمنية. حدد ما إذا كان المكوّن يحتفظ بلقطة طوال عملية واحدة أم يلاحظ التغييرات بين العمليات. تحقق من القيم المعاد تحميلها، وراع التزامن والتنظيف عندما يستبدل الإعداد موردا. لا يكفي الإشعار وحده لإعادة بناء كل كائن تابع بأمان.

وثّق المصادر، والقيم الافتراضية، والمفاتيح المطلوبة، وتسليم الأسرار وتدويرها، والتحقق، وتوقعات إعادة التحميل، وتجاوزات النشر. ينبغي أن تغطي الاختبارات القيم الغائبة والمشوهة والخارجة عن المدى والمستبدلة والمتغيرة، باستخدام مصادر معزولة. لا تقرأ هذه الدورة أسرارا مهيأة، ولا تغيّر إعدادات التطبيق أو الإعدادات العامة.

الأخطاء الشائعة وإصلاحها

يستخدم اختبار قيمة من بيئة الجهاز على نحو غير متوقع.

لماذا يحدث؟
تقرأ القيم الافتراضية للمضيف مصادر خارج نطاق بيانات الاختبار المقصودة.
كيف تصلحه؟
أنشئ موفّرات صريحة ومعزولة لذلك الاختبار.
كيف تتجنب تكراره؟
وثّق ترتيب المصادر والقيم التي تستبدل غيرها.

يُفترض أن الخيارات الصحيحة تعيد تحميل خدمة مفردة النسخة تلقائيا.

لماذا يحدث؟
اختلط إشعار الموفّر بمدة حياة المستهلك.
كيف تصلحه؟
اختر تجريد الخيارات المناسب وسياسة الاستجابة للتغيير.
كيف تتجنب تكراره؟
اختبر القيم المحتفظ بها مقابل القيم التي تُلاحظ تحديثاتها.

يكشف فشل التحقق الأسرار في السجلات.

لماذا يحدث؟
يُستخدم كائن الإعداد كاملا مادة للتشخيص.
كيف تصلحه؟
سجّل سياقا آمنا للمفتاح والفئة، واحجب القيم الحساسة.
كيف تتجنب تكراره؟
راجع مسارات الخطأ بمدخلات اصطناعية تشبه الأسرار.

اختبر فهمك

1. تعتمد خدمة مفردة النسخة على IOptionsSnapshot<T>. لماذا يثير ذلك مسألة تتعلق بمدة الحياة؟

اعرض الحل المشروح

خيارات اللقطة ذات نطاق، بينما تعيش الخدمة المفردة طوال عمر التطبيق أو حاوية الاعتماديات. قد يخالف الاحتفاظ بها النطاق المقصود ويخفي سلوك إعادة التحميل. اختر تجريدا للخيارات متوافقا مع مدة الحياة، أو أنشئ نطاقا صريحا للعملية، ثم اختبر متى تُقرأ القيم ومتى تتحدث. لا يكفي أن يعرض النوع الخاصية الصحيحة لإثبات أن مدة حياته تلائم المستهلك.

2. ما الفرق بين اختبار IOptions.Value واختبار ValidateOnStart؟

اعرض الحل المشروح

قد تنشئ قراءة Value نسخة خيارات وتتحقق منها عبر حقن الاعتماديات. أما ValidateOnStart فمتكاملة مع بدء المضيف، ويلزم تنفيذ ذلك المسار لاختبارها. احتفظ باختبارات المكوّن لقواعد التحقق، وأضف اختبار بدء معزولا لعقد فشل البدء الظاهر للمستهلك عندما يكون ذلك مصرحا به. لا تقدّم قراءة خيارات مباشرة دليلا على أن التطبيق يرفض الاستماع عند وجود إعداد غير صالح.

أهم ما تعلمته

  • ترتيب الموفّرات، والاستهلاك ذو النوع المحدد، والتحقق، وإعادة التحميل عقود منفصلة.
  • يجب أن تتوافق تجريدات الخيارات مع مدد حياة المستهلكين.
  • يجب ألا تكشف معالجة أخطاء الإعداد الأسرار أو تبدأ العمل بتهيئة جزئية.

المراجع الرسمية