مقدمه
یکی از ویژگیهای برجستهی ASP.NET Core، پشتیبانی داخلی از Dependency Injection (DI) است. این قابلیت یکی از اصول اساسی در معماری نرمافزار مدرن محسوب میشود و به توسعهدهندگان اجازه میدهد تا برنامههایی منعطفتر، قابلتستتر و قابلنگهداریتر طراحی کنند.
در گذشته، برنامهنویسان اغلب وابستگیها را بهصورت مستقیم درون کلاسها ایجاد میکردند. اما این روش باعث میشد تغییر و تست کد دشوار شود. با معرفی DI در .NET Core، مایکروسافت یک چارچوب قدرتمند و ساده برای مدیریت وابستگیها ارائه داد که به شکل پیشفرض در هستهی ASP.NET Core قرار دارد.
مفهوم وابستگی (Dependency) در نرمافزار
هر زمان که یک کلاس برای انجام وظایف خود به شیء یا کلاسی دیگر نیاز داشته باشد، میگوییم آن کلاس به کلاس دیگر وابسته (Dependent) است.
نمونهای از وابستگی مستقیم:
در این مثال، کلاس OrderService به طور مستقیم نمونهای از OrderRepository میسازد. این روش باعث میشود که تغییر پیادهسازی OrderRepository نیازمند تغییر مستقیم در OrderService باشد و تستپذیری کاهش یابد.
مفهوم Dependency Injection
Dependency Injection روشی است برای جداسازی وابستگیها از کلاس اصلی. به جای اینکه کلاس خودش وابستگیهایش را بسازد، آنها از بیرون به آن تزریق میشوند.
نسخهی بهبودیافتهی مثال بالا:
با استفاده از این الگو، OrderService وابسته به یک اینترفیس است نه پیادهسازی مشخص. این رویکرد امکان تعویض پیادهسازیها بدون تغییر در منطق را فراهم میکند و تستکردن را ساده میسازد.
آشنایی با IoC (Inversion of Control)
Inversion of Control (IoC) مفهومی است که در آن کنترل ساخت و مدیریت اشیاء از دست کلاسها گرفته میشود و به یک بخش دیگر (Container یا Framework) واگذار میشود. در ASP.NET Core، این کار توسط IoC Container داخلی انجام میشود.
IoC Container وظایف زیر را برعهده دارد:
- شناسایی وابستگیها
- ایجاد نمونههای مناسب از سرویسها
- تزریق نمونهها در زمان مناسب
پیکربندی DI در ASP.NET Core
در ASP.NET Core، همهچیز از متد ConfigureServices در فایل Program.cs یا Startup.cs شروع میشود. در این متد، سرویسها و وابستگیهای مورد نیاز برنامه ثبت (Register) میشوند.
در این مثال:
- IOrderRepository با پیادهسازی OrderRepository ثبت شده است.
- OrderService نیز در Container ثبت شده است.
- در زمان نیاز به OrderService، ASP.NET Core نمونههای مورد نیاز را به صورت خودکار تزریق میکند.
انواع Service Lifetime در ASP.NET Core
در زمان ثبت سرویسها باید مشخص کنید هر سرویس چه مدت در حافظه باقی بماند. سه نوع اصلی وجود دارد:
Transient
هر بار که از سرویس استفاده شود، یک نمونهی جدید ساخته میشود.
مناسب برای: سرویسهای سبک و بدون وضعیت (stateless).
Scoped
برای هر درخواست HTTP یک نمونه جدید ساخته میشود و در طول آن درخواست از همان نمونه استفاده میشود.
مناسب برای: سرویسهایی که دادههای مرتبط با هر درخواست را نگهداری میکنند (مانند DbContext).
Singleton
تنها یک نمونه از سرویس در کل طول عمر برنامه ساخته میشود و همهی درخواستها از همان نمونه استفاده میکنند.
مناسب برای: سرویسهایی که وضعیت ثابتی دارند و thread-safe هستند.
مثال عملی از Dependency Injection
در این مثال ساده، یک سرویس ارسال ایمیل را با DI پیادهسازی میکنیم.
۱. تعریف اینترفیس
۲. پیادهسازی سرویس
۳. ثبت سرویس در Program.cs
۴. تزریق در کنترلر یا Endpoint
ASP.NET Core به طور خودکار نمونهی SmtpEmailService را تزریق میکند و نیاز به new کردن دستی وجود ندارد.
مدیریت وابستگیهای پیچیده
در پروژههای بزرگ ممکن است یک سرویس خود وابسته به چند سرویس دیگر باشد. DI Container به صورت بازگشتی این وابستگیها را حل میکند.
کافی است در Program.cs همهی سرویسها را ثبت کنید؛ بقیه کار توسط DI Container انجام میشود.
نکات حرفهای در استفاده از Dependency Injection
- همیشه از Interface استفاده کنید. وابستگی به اینترفیس باعث جداسازی بهتر لایهها میشود.
- از Service Locator اجتناب کنید. به جای درخواست مستقیم سرویسها از Container، از تزریق Constructor یا تزریق متد استفاده کنید.
- در Singletonها از سرویس Scoped استفاده نکنید. این کار موجب خطاهای عمر سرویس (lifetime mismatch) میشود.
- تست واحد را جدی بگیرید. با DI میتوانید بهراحتی Mock یا Fake برای تست فراهم کنید.
خطاهای رایج در پیادهسازی DI
- عدم ثبت سرویس: اگر سرویسی را ثبت نکنید، در زمان اجرا خطای "Unable to resolve service for type" را خواهید دید.
- تزریق اشتباه Lifetime: استفاده نادرست از Scoped و Singleton میتواند باعث اشتراک ناخواستهی وضعیت بین درخواستها شود.
- وابستگیهای چرخشی (Circular Dependencies): هنگامی که دو سرویس به صورت متقابل به هم نیاز داشته باشند، باید معماری را بازنگری کنید (معمولاً با استخراج رابط یا استفاده از الگوهای دیگری مانند Events حل میشود).
مزایای استفاده از Dependency Injection
خلاصهای از مزایا:
- کاهش coupling بین کلاسها
- افزایش قابلیت تست و امکان Mock کردن سرویسها
- تعویض آسان پیادهسازیها بدون تغییر در منطق کسبوکار
- کدنویسی خواناتر و قابل نگهداریتر
- پشتیبانی داخلی ASP.NET Core بدون نیاز به کتابخانه خارجی
جمعبندی
در این مقاله آموختیم که Dependency Injection یکی از اصول کلیدی در معماری مدرن .NET Core است که باعث میشود پروژهها ساختاری منظم، قابل تست و منعطف داشته باشند. ASP.NET Core با IoC Container داخلی خود، این فرآیند را بسیار ساده کرده و تنها با چند خط کد میتوان وابستگیها را مدیریت کرد.
توئیتر
تلگرام
لینکدین
فیسبوک
ایتا
روبیکا
محمد شاه نظرلی
برنامهنویس و توسعهدهنده نرمافزار با بیش از ۱۵ سال تجربه در داتنت، طراحی سامانههای سازمانی و بهینهسازی سئو.
علاقهمند به اشتراکگذاری دانش و یادگیری مستمر.
دیدگاه خود را ارسال کنید