مقدمه
وابستگیتزریقی (Dependency Injection یا DI) یکی از مفاهیم کلیدی در توسعه برنامههای مدرن با ASP.NET Core است که به ایجاد کدهایی با قابلیت تستپذیری بالا، نگهداری آسان و انعطافپذیری بیشتر کمک میکند. با این حال، در پروژههای بزرگ، ثبت دستی تمام سرویسها و وابستگیها میتواند زمانبر و مستعد خطا باشد. اینجاست که ابزارهایی مانند Scrutor وارد میدان میشوند. Scrutor یک کتابخانه متنباز است که با افزودن قابلیتهای اسکن خودکار اسمبلیها و ثبت سرویسها، فرآیند وابستگیتزریقی را سادهتر و کارآمدتر میکند. در این مقاله، با مفاهیم اصلی Scrutor، نحوه استفاده از آن برای خودکارسازی ثبت وابستگیها و نکات کلیدی برای بهرهبرداری بهینه در پروژههای ASP.NET Core آشنا میشویم.
Scrutor چیست و چرا به آن نیاز داریم؟
Scrutor یک افزونه برای ظرف وابستگیتزریقی داخلی ASP.NET Core (Microsoft.Extensions.DependencyInjection) است که قابلیتهایی مانند اسکن خودکار اسمبلیها و تزئین سرویسها (Decoration) را ارائه میدهد. برخلاف سایر ظرفهای وابستگیتزریقی مانند Autofac یا Ninject، Scrutor خود یک ظرف کامل نیست، بلکه ابزار کمکیای است که روی ظرف داخلی مایکروسافت کار میکند. این ویژگی باعث میشود Scrutor سبک، ساده و کاملاً سازگار با اکوسیستم ASP.NET Core باشد.
نیاز به Scrutor زمانی احساس میشود که تعداد سرویسها و پیادهسازیهای آنها در پروژه افزایش مییابد. ثبت دستی هر سرویس، مانند نمونه زیر، میتواند کد را شلوغ و مدیریت آن را دشوار کند:
services.AddScoped<IUserService, UserService>();
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IPaymentService, PaymentService>();
Scrutor با اسکن اسمبلیها و ثبت خودکار سرویسها بر اساس قراردادهای مشخص، این فرآیند را ساده میکند و از تکرار کدهای اضافی جلوگیری میکند.
نصب و راهاندازی Scrutor
برای شروع کار با Scrutor، ابتدا باید بسته آن را از طریق NuGet نصب کنید. این کار با اجرای دستور زیر در کنسول مدیریت بستهها یا CLI داتنت انجام میشود:
dotnet add package Scrutor
پس از نصب، میتوانید از متدهای افزونه Scrutor در متد ConfigureServices یا Program.cs (در پروژههای Minimal API) استفاده کنید.
اسکن خودکار اسمبلیها
یکی از قدرتمندترین قابلیتهای Scrutor، اسکن خودکار اسمبلیها برای یافتن و ثبت سرویسهاست. این ویژگی به توسعهدهندگان اجازه میدهد تا به جای ثبت دستی هر سرویس، از قراردادهایی مانند تطابق نام رابطها و پیادهسازیها استفاده کنند. به عنوان مثال، فرض کنید رابطها و پیادهسازیهای زیر را در پروژه خود دارید:
public interface IUserService { }
public class UserService : IUserService { }
public interface IOrderService { }
public class OrderService : IOrderService { }برای ثبت خودکار این سرویسها، میتوانید از متد Scan استفاده کنید:
builder.Services.Scan(scan => scan
.FromCallingAssembly()
.AddClasses()
.AsMatchingInterface()
.WithScopedLifetime());در این کد:
FromCallingAssembly() مشخص میکند که اسکن در اسمبلی فعلی انجام شود.AddClasses() تمام کلاسهای غیرانتزاعی و عمومی را انتخاب میکند.AsMatchingInterface() رابطهایی را که با نام کلاسها تطابق دارند (مانند IUserService برای UserService) ثبت میکند.WithScopedLifetime() طول عمر سرویسها را بهصورت محدود به درخواست (Scoped) تنظیم میکند.
این روش نهتنها کد را تمیزتر میکند، بلکه با افزودن سرویسهای جدید، نیازی به تغییر کد ثبت نیست.
استفاده از نشانگرهای اسمبلی
در پروژههای بزرگ که چندین اسمبلی دارند، ممکن است بخواهید فقط سرویسهای موجود در اسمبلیهای خاصی را ثبت کنید. یک روش متداول، استفاده از رابطهای نشانگر (Marker Interfaces) است. برای مثال، فرض کنید رابط زیر را در اسمبلی مورد نظر تعریف کردهاید:
public interface IApplicationAssemblyMarker { }سپس میتوانید از آن برای اسکن سرویسها استفاده کنید:
builder.Services.Scan(scan => scan
.FromAssemblyOf<IApplicationAssemblyMarker>()
.AddClasses()
.AsImplementedInterfaces()
.WithScopedLifetime());این روش به شما امکان میدهد تا دامنه اسکن را به یک اسمبلی خاص محدود کنید و از ثبت سرویسهای غیرضروری جلوگیری کنید.
مدیریت طول عمر سرویسها
یکی از نکات مهم در استفاده از Scrutor، انتخاب طول عمر مناسب برای سرویسهاست. ASP.NET Core سه نوع طول عمر را پشتیبانی میکند:
- Transient: هر بار که سرویس درخواست شود، یک نمونه جدید ایجاد میشود.
- Scoped: یک نمونه در طول یک درخواست HTTP به اشتراک گذاشته میشود.
- Singleton: یک نمونه برای کل عمر برنامه استفاده میشود.
Scrutor به شما اجازه میدهد طول عمر را بهصورت یکپارچه برای تمام سرویسهای ثبتشده تعیین کنید. با این حال، باید دقت کنید که انتخاب نادرست طول عمر میتواند به مشکلات عملکردی یا ناسازگاری دادهها منجر شود. بهطور کلی، طول عمر Scoped برای اکثر سرویسهای وب مناسب است، مگر اینکه دلایل خاصی برای استفاده از Transient یا Singleton وجود داشته باشد.
نکات بهترین تمرینها
برای استفاده بهینه از Scrutor، رعایت چند نکته کلیدی ضروری است:
- سازماندهی مناسب رابطها و پیادهسازیها: نامگذاری یکپارچه (مانند پیشوند
I برای رابطها) و قرار دادن کلاسها در فضای نامی مناسب، فرآیند اسکن را سادهتر میکند. - آزمایش پیکربندی DI: از تستهای یکپارچگی برای اطمینان از ثبت صحیح سرویسها استفاده کنید.
- مدیریت نسخهها: هنگام بهروزرسانی Scrutor، سازگاری با نسخههای ASP.NET Core را بررسی کنید.
- مستندسازی قراردادها: اگر از قراردادهای پیچیده برای ثبت سرویسها استفاده میکنید، آنها را مستند کنید تا تیمهای دیگر بهراحتی متوجه منطق شوند.
مقایسه با سایر ابزارها
Scrutor در مقایسه با ابزارهایی مانند Autofac سبکتر است و پیچیدگی کمتری به پروژه اضافه میکند. Autofac قابلیتهای پیشرفتهتری مانند تزریق ویژگیها (Property Injection) ارائه میدهد، اما ممکن است برای پروژههای کوچکتر بیش از حد پیچیده باشد. Scrutor با تمرکز بر سادگی و ادغام بومی با ASP.NET Core، انتخابی عالی برای پروژههایی است که نیازی به ویژگیهای پیچیده ندارند.
نتیجهگیری
Scrutor ابزاری قدرتمند و سبک برای خودکارسازی ثبت وابستگیها در ASP.NET Core است که با کاهش کدهای تکراری، توسعه و نگهداری پروژهها را آسانتر میکند. قابلیت اسکن خودکار اسمبلیها و انعطافپذیری در تنظیم قراردادها، آن را به گزینهای ایدهآل برای توسعهدهندگان داتنت تبدیل کرده است. با رعایت بهترین تمرینها و انتخاب مناسب طول عمر سرویسها، میتوانید از Scrutor برای ایجاد برنامههایی تمیز، مقیاسپذیر و قابل تست استفاده کنید. اگر به دنبال راهی برای سادهسازی فرآیند وابستگیتزریقی در پروژههای خود هستید، Scrutor قطعاً ارزش امتحان کردن را دارد.
مراجع