Scrutor لـ C# (.NET): دليل شامل مع أمثلة
Scrutor هي مكتبة مفتوحة المصدر لمنصة .NET تعمل على توسيع آلية حقن التبعية (Dependency Injection - DI) المدمجة بإمكانية المسح التلقائي للتجميعات (assembly scanning). تتيح لك تسجيل الخدمات في حاوية DI بناءً على اصطلاحات التسمية أو السمات أو الواجهات، مما يبسط بشكل كبير إعداد حاوية IoC في المشاريع الكبيرة.
لماذا تحتاج هذه المكتبة؟ في الحاوية القياسية Microsoft.Extensions.DependencyInjection، يجب تسجيل كل خدمة يدوياً: services.AddScoped<IMyService, MyService>(). في مشروع يحتوي على عشرات أو مئات الخدمات، يؤدي ذلك إلى تضخم الكود في ملف Startup.cs أو Program.cs، ويقلل من قابلية القراءة ويزيد من خطر الأخطاء. تحل Scrutor هذه المشكلة بالسماح بتسجيل جميع الخدمات من تجميع معين بسطر واحد: services.Scan(scan => scan.FromAssemblyOf<IMyService>()...).
تكون Scrutor مفيدة بشكل خاص في البنى التي تستخدم التصميم القائم على المجال (DDD) أو Clean Architecture أو الوحدات المتجانسة. فهي تبحث تلقائياً عن جميع تطبيقات الواجهات، والفئات التي تحتوي على سمات محددة (مثل [ServiceDescriptor])، أو الفئات التي تطابق أنماط تسمية معينة (مثل جميع الفئات التي تنتهي بـ "Repository"). وهذا يجعل الكود أنظف، وإضافة خدمات جديدة مهمة بسيطة لا تتطلب تغيير إعدادات DI.
التثبيت
يتم تثبيت Scrutor عبر NuGet Package Manager. نفّذ أحد الأوامر التالية:
# عبر .NET CLI
dotnet add package Scrutor
# عبر Package Manager Console (Visual Studio)
Install-Package Scrutor
بعد التثبيت، ستتم إضافة مرجع إلى مكتبة Scrutor في المشروع. تأكد من تثبيت .NET SDK الإصدار 6.0 أو أعلى (يُوصى باستخدام .NET 8.0+).
بداية سريعة
لننظر إلى مثال عملي بسيط. سننشئ تطبيق وحدة تحكم بثلاثة ملفات: واجهة IGreetingService، وتنفيذها GreetingService، ونقطة الدخول Program.cs.
// IGreetingService.cs
public interface IGreetingService
{
string Greet(string name);
}
// GreetingService.cs
public class GreetingService : IGreetingService
{
public string Greet(string name) => $"Hello, {name}!";
}
// Program.cs
using Microsoft.Extensions.DependencyInjection;
using Scrutor;
var services = new ServiceCollection();
// التسجيل اليدوي (الطريقة التقليدية)
// services.AddTransient<IGreetingService, GreetingService>();
// التسجيل عبر Scrutor (مسح التجميع)
services.Scan(scan => scan
.FromAssemblyOf<IGreetingService>() // مسح التجميع الذي يحتوي على IGreetingService
.AddClasses(classes => classes.AssignableTo<IGreetingService>()) // البحث عن الفئات التي تطبق IGreetingService
.AsImplementedInterfaces() // التسجيل كتطبيق للواجهة
.WithTransientLifetime()); // تعيين عمر الخدمة كـ Transient
var serviceProvider = services.BuildServiceProvider();
var greetingService = serviceProvider.GetRequiredService<IGreetingService>();
Console.WriteLine(greetingService.Greet("World"));
// الإخراج: Hello, World!
في هذا المثال، يجد Scrutor تلقائياً الفئة GreetingService في نفس التجميع الذي توجد فيه الواجهة IGreetingService، ويسجلها كخدمة Transient. إذا أضفت تطبيقاً جديداً لـ IGreetingService، فسيتم تسجيله تلقائياً دون الحاجة لتغيير كود Program.cs.
الطرق والفئات الأساسية
يوفر Scrutor واجهة برمجة fluent API لبناء سلاسل الاستدعاءات. دعنا نستعرض 8 طرق/فئات رئيسية مع التوقيع والشرح والأمثلة.
1. Scan(IServiceCollection, Action<ITypeSourceSelector>)