مدد حياة الخدمات: Transient وScoped وSingleton
تعلّموا كيف تؤثر مدد حياة Transient وScoped وSingleton في إنشاء الكائنات ومشاركتها والتخلص منها.
مدد حياة الخدمات: Transient وScoped وSingleton درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.
لماذا تهم مدد الحياة
تحدد مدة حياة الخدمة المدة التي يعيشها المثيل وعدد المثيلات التي يتم إنشاؤها. وقد يؤدي اختيار مدة الحياة الخاطئة إلى أخطاء خفية، مثل تسرّب البيانات بين الطلبات أو إنشاء عدد مفرط من الكائنات.
Transient: مثيل جديد في كل مرة
تُنشأ خدمات Transient من جديد في كل مرة تُطلب فيها من الحاوية. استخدموها للخدمات الخفيفة عديمة الحالة، حيث قد تكون مشاركة الحالة خطرة.
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)Scoped: مرة واحدة لكل طلب
تُنشأ خدمات Scoped مرة واحدة لكل نطاق، ويكون ذلك عادةً طلب HTTP واحدًا في ASP.NET Core. ويُشارك المثيل نفسه طوال الطلب، ثم يُنشأ مثيل جديد للطلب التالي.
builder.Services.AddScoped<AppDbContext>();
// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the requestSingleton: واحد طوال مدة حياة التطبيق
تُنشأ خدمات Singleton مرة واحدة ويُعاد استخدامها طوال مدة حياة التطبيق. استخدموها للخدمات المكلفة عند إنشائها والآمنة للاستخدام المتزامن، مثل ذاكرات التخزين المؤقت للإعدادات.
builder.Services.AddSingleton<IMemoryCache, MemoryCache>();
// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);مقارنة مدد الحياة الثلاث
مقارنة سريعة:
- Transient — مثيل جديد مع كل طلب؛ للأدوات عديمة الحالة
- Scoped — مثيل واحد لكل طلب HTTP؛ مثل DbContext ووحدة العمل
- Singleton — مثيل واحد طوال مدة حياة التطبيق؛ لذاكرات التخزين المؤقت والإعدادات
مشكلة التبعية الأسيرة
يُعد حقن خدمة Scoped أو Transient داخل خدمة Singleton خطأً شائعًا. إذ يحتفظ Singleton بمرجع إلى الخدمة قصيرة العمر، مما يبقيها حيةً مدة أطول من اللازم.
// BAD: Singleton captures a Scoped service
public class MySingleton
{
private readonly AppDbContext _db; // Scoped!
public MySingleton(AppDbContext db) => _db = db;
// _db is now stuck alive for the app's lifetime
}اكتشاف انتهاكات النطاق
فعّلوا ValidateScopes لكي ترمي الحاوية استثناءً عند بدء التشغيل إذا اكتشفت تبعية أسيرة. ويساعد ذلك على اكتشاف الأخطاء قبل أن تتسبب في مشكلات بيانات في بيئة الإنتاج.
builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true; // detect captive deps
options.ValidateOnBuild = true; // fail fast at start
});الخدمات Scoped خارج الطلب
لحلّ خدمات Scoped في مهمة تعمل في الخلفية، أنشئوا نطاقًا صريحًا باستخدام IServiceScopeFactory. لا تحلّوا خدمات Scoped مباشرةً من الحاوية الجذرية مطلقًا.
public class MyWorker : BackgroundService
{
private readonly IServiceScopeFactory _factory;
public MyWorker(IServiceScopeFactory factory) => _factory = factory;
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var scope = _factory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Users.ToListAsync(ct);
}
}خدمات Transient القابلة للتخلص
تتبع خدمات IDisposable من نوع Transient التي تُحلّ من الحاوية الجذرية حتى يتم التخلص من الحاوية، أي عند إيقاف التطبيق. احلّوها داخل نطاق لتحرير الموارد بسرعة.
// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposedاختيار مدة الحياة المناسبة
دليل قرار بسيط:
- هل الخدمة عديمة الحالة؟ → Transient
- هل تعتمد على طلب، مثل هوية المستخدم أو DbContext؟ → Scoped
- هل هي آمنة للاستخدام المتزامن ومكلفة عند إنشائها؟ → Singleton
من الواقع العملي: مدد الحياة الثلاث معًا
تسجّل واجهة برمجة تطبيقات ويب نموذجية خدمات مختلفة بمدد حياة مناسبة لضمان الصحة وتحقيق الأداء.
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddSingleton<ICacheService, RedisCacheService>();
builder.Services.AddScoped<AppDbContext>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();
builder.Services.AddTransient<IEmailSender, SendGridEmailSender>();تحقق سريع
ما المشكلة التي تحدث عندما تحتفظ خدمة Singleton بمرجع إلى خدمة Scoped؟
مراجعة: مدد حياة الخدمات
أهم النقاط:
- Transient: مثيل جديد في كل مرة — مناسب للخدمات الخفيفة عديمة الحالة
- Scoped: مثيل واحد لكل طلب — مثل DbContext والمستودعات ووحدة العمل
- Singleton: مثيل واحد طوال مدة الحياة — مثل ذاكرات التخزين المؤقت والإعدادات والأدوات الآمنة للاستخدام المتزامن
- لا تحقنوا الخدمات قصيرة العمر داخل خدمات أطول عمرًا مطلقًا (التبعية الأسيرة)
- استخدموا
IServiceScopeFactoryلحلّ خدمات Scoped في المهام التي تعمل في الخلفية
تعلم C# مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 93
- الدروس
- 346
الأسئلة الشائعة
هل درس «مدد حياة الخدمات: Transient وScoped وSingleton» مجاني؟
نعم — نص درس «مدد حياة الخدمات: Transient وScoped وSingleton» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «مدد حياة الخدمات: Transient وScoped وSingleton»؟
تعلّموا كيف تؤثر مدد حياة Transient وScoped وSingleton في إنشاء الكائنات ومشاركتها والتخلص منها. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «مدد حياة الخدمات: Transient وScoped وSingleton»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات حاوية DI
- مدد حياة الخدمات: Transient وScoped وSingleton
- الحقن عبر المُنشئ والواجهات
- أنماط Factory وOptions