#DependencyInjection
#InversionOfControl
#DI
#Ioc
انواع تزریق وابستگی
IOC یک اصطلاح جنریک است. به جای اینکه برنامه متدها را در فریم ورک فراخوانی کند، فریم ورک پیاده سازی های برنامه را فراخوانی می کند. تزریق وابستگی شکلی از IOC است، که پیاده سازی ها از طریق سازنده ها/تنظیم کننده ها/ سرویس های lookup به شیء پاس داده می شوند که روی شیء تزریق خواهد شد و به درستی رفتار خواهد کرد. فریم ورک های تزریق وابستگی برای استفاده از DI طراحی شده اند و می توانند رابط ها (interface) را تعریف کرده تا پیاده سازی ها را آسان کنند.
لیست فریم ورک های تزریق وابستگی
در زیر لیستی از نگهدارنده های (container) محبوب تزریق وابستگی را شرح می دهیم.
Spring.NET
Spring.NET یکی از فریم ورک های open source محبوب برای تزریق وابستگی است که NET 4.0.، NET Client Profile 3.5. و 4.0، Silverlight 4.0 و 5.0 و Windows Phone 7.0 و 7.1 را پشتیبانی می کند.
Castle Windsor
Castle Windsor یک کانتینر کامل IOC برای .NET و Silverlight است. ورژن فعلی آن 4.0 است که در جولای 2017 منتشر شد. Castle Windsor را می توان از GitHub یا NuGet دانلود کرد. مزایای استفاده از Castle Windsor این است که کامل بوده و با decorator آشناست و به خوبی مستندشده است.
Unity
Unity (Unity Application Block) یک کانتینر تزریق وابستگی کم وزن و توسعه پذیر است که نسبتا پیچیده تر می باشد. Unity از کانتینر و داده های XML استفاده می کند و پشتیبانی قدرتمندی از XML داشته و با برنامه های WPF کار می کند. تحت مجوز عمومی مایکروسافت بوده و رایگان است. Unity به صورتمسأله هایی که توسعه دهندگان در مهندسی نرم افزار مبتنی بر مولفه با آن درگیرند می پردازد. همچنین شامل افزونه Interception container است که به توسعه دهنگان اجازه می دهد تا مدیریت exception، logging یا حتی کدهای سفارشی خود بین فراخواننده و فراخوانده شده را تزریق کنند.
Structure Map
Structure Map تزریق وابستگی برای .NET است که می تواند برای بهبود کیفیت معماری سیستم شیءگرا با کاهش هزینه های ماشینی تکنولوژی های طراحی خوب مورد استفاده قرار گیرد. تحت مجوز Apache 2 OSS منتشر شده است، رایگان میباشد و توسعهدهنده میتواند آن را دانلود کرده، تغییر دهد و مجددا توزیع کند.
Autofac
Autofac کانتینر IOC برای #Microsoft .NET C، ورژنهای 3.0 و بالاتر میباشد. مجوز آن تحت MIT است. وابستگیهای میان کلاسها را مدیریت میکند، چنان که برنامهها با تغییر در اندازه و پیچیدگی، همچنان آسان باقی بمانند.
Ninject
یک فریمورک تزریق وابستگی همگانی، فوقالعاده سبک و open source برای .NET، Mono، .NET Compact Framework و Silverlight میباشد. مجوز آن تحت Apache 2 است. Ninject به شما کمک میکند تا از تکنیکهای تزریق وابستگی برای شکستن برنامهیتان به اجزای کاملا یکپارچه و پیوسته بدون محدودیت استفاده کنید، و سپس آنها را به صورت انعطافپذیر به هم متصل میکند.
مزایای تزریق وابستگی
تزریق وابستگی به جداسازی کلاسها کمک میکند. DI و IOC کار را برای توسعهدهنده آسان میکنند تا بتواند وابستگی بین اشیاء را مدیریت کند. این امر باعث میشود تا توسعهدهنده راحتتر بتواند ارتباطات اساسی را با قراردادهای خود نشان دهد. در نتیجه کدها ماژولارتر میشوند. همچنین قابلیت استفاده مجدد کدها افزایش یافته و نگهداری و تست کدها بهبود مییابد.
معایب تزریق وابستگی
درک کد شما میتواند سختتر شود. تزریق وابستگی معمولا با افزایش تعداد کلاسها، که همیشه هم مفید نیستند، پیچیدگی کد را بالا میبرد. به طور کلی مزیت جداسازی، خواندن و درک هر کار را سادهتر میکند، اما پیچیدگی هماهنگی بین کارهای پیچیدهتر را افزایش میدهد.
تزریق وابستگی منحنی یادگیری بالاتری را دارد. برای درک نحوه استفاده یک پروژه از تزریق وابستگی، توسعهدهنده باید هم الگوی تزریق وابستگی و هم فریمورکهای خاص را درک کند.
با استفاده از فریمورک تزریق وابستگی، کلاینتها به پیکربندی داده وابسته هستند. این کار وقتی برنامه نیازی به پیکربندی سفارشی زیادی ندارد، برای توسعهدهندگان یک کار اضافی محسوب میشود.
نتیجهگیری
محبوبیت تزریق وابستگی در جامعه توسعهدهندگان همچنان رو به رشد است. IOC در مورد اینکه چه کسی شروع به برقراری تماس میکند، صحبت میکند، در حالی که DI در مورد نحوه دستیابی وابستگی یک شیء روی اشیای دیگر، از طریق انتزاع (abstraction)، صحبت میکند. اگر از تزریق وابستگی استفاده میکنید، سبکهای زیادی برای انتخاب بین آنها وجود دارد
@ABlueDeveloper
#InversionOfControl
#DI
#Ioc
انواع تزریق وابستگی
IOC یک اصطلاح جنریک است. به جای اینکه برنامه متدها را در فریم ورک فراخوانی کند، فریم ورک پیاده سازی های برنامه را فراخوانی می کند. تزریق وابستگی شکلی از IOC است، که پیاده سازی ها از طریق سازنده ها/تنظیم کننده ها/ سرویس های lookup به شیء پاس داده می شوند که روی شیء تزریق خواهد شد و به درستی رفتار خواهد کرد. فریم ورک های تزریق وابستگی برای استفاده از DI طراحی شده اند و می توانند رابط ها (interface) را تعریف کرده تا پیاده سازی ها را آسان کنند.
لیست فریم ورک های تزریق وابستگی
در زیر لیستی از نگهدارنده های (container) محبوب تزریق وابستگی را شرح می دهیم.
Spring.NET
Spring.NET یکی از فریم ورک های open source محبوب برای تزریق وابستگی است که NET 4.0.، NET Client Profile 3.5. و 4.0، Silverlight 4.0 و 5.0 و Windows Phone 7.0 و 7.1 را پشتیبانی می کند.
Castle Windsor
Castle Windsor یک کانتینر کامل IOC برای .NET و Silverlight است. ورژن فعلی آن 4.0 است که در جولای 2017 منتشر شد. Castle Windsor را می توان از GitHub یا NuGet دانلود کرد. مزایای استفاده از Castle Windsor این است که کامل بوده و با decorator آشناست و به خوبی مستندشده است.
Unity
Unity (Unity Application Block) یک کانتینر تزریق وابستگی کم وزن و توسعه پذیر است که نسبتا پیچیده تر می باشد. Unity از کانتینر و داده های XML استفاده می کند و پشتیبانی قدرتمندی از XML داشته و با برنامه های WPF کار می کند. تحت مجوز عمومی مایکروسافت بوده و رایگان است. Unity به صورتمسأله هایی که توسعه دهندگان در مهندسی نرم افزار مبتنی بر مولفه با آن درگیرند می پردازد. همچنین شامل افزونه Interception container است که به توسعه دهنگان اجازه می دهد تا مدیریت exception، logging یا حتی کدهای سفارشی خود بین فراخواننده و فراخوانده شده را تزریق کنند.
Structure Map
Structure Map تزریق وابستگی برای .NET است که می تواند برای بهبود کیفیت معماری سیستم شیءگرا با کاهش هزینه های ماشینی تکنولوژی های طراحی خوب مورد استفاده قرار گیرد. تحت مجوز Apache 2 OSS منتشر شده است، رایگان میباشد و توسعهدهنده میتواند آن را دانلود کرده، تغییر دهد و مجددا توزیع کند.
Autofac
Autofac کانتینر IOC برای #Microsoft .NET C، ورژنهای 3.0 و بالاتر میباشد. مجوز آن تحت MIT است. وابستگیهای میان کلاسها را مدیریت میکند، چنان که برنامهها با تغییر در اندازه و پیچیدگی، همچنان آسان باقی بمانند.
Ninject
یک فریمورک تزریق وابستگی همگانی، فوقالعاده سبک و open source برای .NET، Mono، .NET Compact Framework و Silverlight میباشد. مجوز آن تحت Apache 2 است. Ninject به شما کمک میکند تا از تکنیکهای تزریق وابستگی برای شکستن برنامهیتان به اجزای کاملا یکپارچه و پیوسته بدون محدودیت استفاده کنید، و سپس آنها را به صورت انعطافپذیر به هم متصل میکند.
مزایای تزریق وابستگی
تزریق وابستگی به جداسازی کلاسها کمک میکند. DI و IOC کار را برای توسعهدهنده آسان میکنند تا بتواند وابستگی بین اشیاء را مدیریت کند. این امر باعث میشود تا توسعهدهنده راحتتر بتواند ارتباطات اساسی را با قراردادهای خود نشان دهد. در نتیجه کدها ماژولارتر میشوند. همچنین قابلیت استفاده مجدد کدها افزایش یافته و نگهداری و تست کدها بهبود مییابد.
معایب تزریق وابستگی
درک کد شما میتواند سختتر شود. تزریق وابستگی معمولا با افزایش تعداد کلاسها، که همیشه هم مفید نیستند، پیچیدگی کد را بالا میبرد. به طور کلی مزیت جداسازی، خواندن و درک هر کار را سادهتر میکند، اما پیچیدگی هماهنگی بین کارهای پیچیدهتر را افزایش میدهد.
تزریق وابستگی منحنی یادگیری بالاتری را دارد. برای درک نحوه استفاده یک پروژه از تزریق وابستگی، توسعهدهنده باید هم الگوی تزریق وابستگی و هم فریمورکهای خاص را درک کند.
با استفاده از فریمورک تزریق وابستگی، کلاینتها به پیکربندی داده وابسته هستند. این کار وقتی برنامه نیازی به پیکربندی سفارشی زیادی ندارد، برای توسعهدهندگان یک کار اضافی محسوب میشود.
نتیجهگیری
محبوبیت تزریق وابستگی در جامعه توسعهدهندگان همچنان رو به رشد است. IOC در مورد اینکه چه کسی شروع به برقراری تماس میکند، صحبت میکند، در حالی که DI در مورد نحوه دستیابی وابستگی یک شیء روی اشیای دیگر، از طریق انتزاع (abstraction)، صحبت میکند. اگر از تزریق وابستگی استفاده میکنید، سبکهای زیادی برای انتخاب بین آنها وجود دارد
@ABlueDeveloper
#DI
#Ioc
#DIP
#SOLID
✳️ Captive Dependency
🔹 در این پست به توضیح مشکلی میپردازیم که معمولا به دلیل اشتباه کانفیگ کردن سرویس های اپلیکیشن در IOC Container رخ میدهد.
🔸 تزریق وابستگی (Dependency Injection) از مفاهیم مهمی هست که باید به آن آشنا باشیم. برای استفاده از این مفهوم و مفاهیم مرتبط با آن مثل IOC ,DIP
در اپلیکیشن، ابزار ها یا فریم وورک هایی وجود دارند که به آنها IOC Container می گوییم.
🔻اگر با DI و IOC و DIP آشنا نیستید مقالات لینک شده را مطالعه کنید.
🔸مدیریت lifeTime سرویس های اپلیکیشن امری است که به کمک IOC Container مقدر میشود اما وظیفه register کردن و معرفی کردن وابستگی ها به IOC Container بر عهده Developer میباشد.
🔸 اشتباه کانفیگ کردن lifeTime برای سرویسی در اپلیکیشن، که خود دارای وابستگی هایی، با lifeTime ای کمتر از lifeTime سرویس اصلی هستند، باعث به وجود آمد مشکل Captive Dependency میشود.
🔹 برای درک مسئله به مثال زیر توجه کنید
فرض کنید دو کلاس با نام های
ScopedDependency
SingletonDependency
داریم.
🔸 همانطور که از نام ها مشخص است کلاس SingletonDependency به صورت Singleton به DI Contaner معرفی شده و در طول عمر اپلیکیشن فقط یک نمونه از آن ساخته میشود.
🔸 کلاس ScopedDependency هم به صورت Scoped در IOC Container معرفی شده و به ازای هر connection به سرور فقط یک نمونه از آن به ازای هر کانکشن و درخواست ساخته میشود.
🔸 بیایید فرض کنیم که چه اتفاقی می افتد اگر کلاس SingletonDependency برای انجام برخی کارها در درون خود به کلاس ScopedDependency وابسته باشد و ما نیاز داشته باشیم که کلاس ScopedDependency در درون آن تزریق کنیم.
🔹 با رجیستر کردن کلاس ScopedDependency بصورت Scoped انتظار این است که روند نمونه سازی از این کلاس Scoped گونه باشد. اما وقتی این کلاس را در یک کلاس دیگر که به صورت Singleton رجیستر شده است تزریق میکنید، قوائد بازی را برهم زده و باعث میشوید که کلاس Singleton مورد نظر در تمام طول عمر خود فقط از یک نمونه قدیمی از وابستگی خود استفاده کند. این نمونه قدیمی برای اولین بار در هنگام ساخته شدن کلاس Singleton ای که در درون آن وجود دارد ساخته شده و به زندگی خود به لطف حضور در یک کلاس Singleton ادامه میدهد.
پس در نتیجه برای SingletonDepedency ما فقط یک نمونه از ScopedDependency ساخته میشود و در تمام طول عر خود از همان نمونه قدیمی استفاده میکند.
🔸در نگاه اول شاید این مشکل حاد به نظر نرسد اما باید بدانید که در یک پروژه که پیچیدگی های خاص خود را دارد باعث بروز مشکلات و باگ های فاحش خواهد شد.
🔸 این مشکل توسط Developer با اشتباه کانفیگ کردن lifeTime برای سرویس های اپلیکیشن رخ میدهد و حتی IOC Container هایی مانند Autofac نمی توانند از آن جلوگیری کنند.
اما IOC Container پیشفرض Asp.Net Core سعی کرده است تا حدی از این مشکل جلوگیری کند.
🔸 فعال سازی این ویژگی برای IOC Container پیشفرض اختیاری بوده و در صورت فعال سازی آن، نکته ای که باعث بهبود performance میشود این است که فقط در محیط و هنگام Development از آن استفاده کنید.
🔻همچنین باید بدانید که این ویژگی فقط از بروز Captive Dependency برای سرویس هایی که به صورت Scoped رجیستر شده اند، جلوگیری میکند و باعث صادر شدن استثنای InvalidOperationException میشود. و برای سرویس های که به صورت Transient رجیستر شده اند کار نمیکند.
❇️ برای فعال سازی این ویژگی در کلاس Program بدین شکل عمل کنید.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseDefaultServiceProvider((env, c) =>
{
if (env.HostingEnvironment.IsDevelopment())
{
c.ValidateScopes = true;
}
});
}
@FullStackDevs
#Ioc
#DIP
#SOLID
✳️ Captive Dependency
🔹 در این پست به توضیح مشکلی میپردازیم که معمولا به دلیل اشتباه کانفیگ کردن سرویس های اپلیکیشن در IOC Container رخ میدهد.
🔸 تزریق وابستگی (Dependency Injection) از مفاهیم مهمی هست که باید به آن آشنا باشیم. برای استفاده از این مفهوم و مفاهیم مرتبط با آن مثل IOC ,DIP
در اپلیکیشن، ابزار ها یا فریم وورک هایی وجود دارند که به آنها IOC Container می گوییم.
🔻اگر با DI و IOC و DIP آشنا نیستید مقالات لینک شده را مطالعه کنید.
🔸مدیریت lifeTime سرویس های اپلیکیشن امری است که به کمک IOC Container مقدر میشود اما وظیفه register کردن و معرفی کردن وابستگی ها به IOC Container بر عهده Developer میباشد.
🔸 اشتباه کانفیگ کردن lifeTime برای سرویسی در اپلیکیشن، که خود دارای وابستگی هایی، با lifeTime ای کمتر از lifeTime سرویس اصلی هستند، باعث به وجود آمد مشکل Captive Dependency میشود.
🔹 برای درک مسئله به مثال زیر توجه کنید
فرض کنید دو کلاس با نام های
ScopedDependency
SingletonDependency
داریم.
🔸 همانطور که از نام ها مشخص است کلاس SingletonDependency به صورت Singleton به DI Contaner معرفی شده و در طول عمر اپلیکیشن فقط یک نمونه از آن ساخته میشود.
🔸 کلاس ScopedDependency هم به صورت Scoped در IOC Container معرفی شده و به ازای هر connection به سرور فقط یک نمونه از آن به ازای هر کانکشن و درخواست ساخته میشود.
🔸 بیایید فرض کنیم که چه اتفاقی می افتد اگر کلاس SingletonDependency برای انجام برخی کارها در درون خود به کلاس ScopedDependency وابسته باشد و ما نیاز داشته باشیم که کلاس ScopedDependency در درون آن تزریق کنیم.
🔹 با رجیستر کردن کلاس ScopedDependency بصورت Scoped انتظار این است که روند نمونه سازی از این کلاس Scoped گونه باشد. اما وقتی این کلاس را در یک کلاس دیگر که به صورت Singleton رجیستر شده است تزریق میکنید، قوائد بازی را برهم زده و باعث میشوید که کلاس Singleton مورد نظر در تمام طول عمر خود فقط از یک نمونه قدیمی از وابستگی خود استفاده کند. این نمونه قدیمی برای اولین بار در هنگام ساخته شدن کلاس Singleton ای که در درون آن وجود دارد ساخته شده و به زندگی خود به لطف حضور در یک کلاس Singleton ادامه میدهد.
پس در نتیجه برای SingletonDepedency ما فقط یک نمونه از ScopedDependency ساخته میشود و در تمام طول عر خود از همان نمونه قدیمی استفاده میکند.
🔸در نگاه اول شاید این مشکل حاد به نظر نرسد اما باید بدانید که در یک پروژه که پیچیدگی های خاص خود را دارد باعث بروز مشکلات و باگ های فاحش خواهد شد.
🔸 این مشکل توسط Developer با اشتباه کانفیگ کردن lifeTime برای سرویس های اپلیکیشن رخ میدهد و حتی IOC Container هایی مانند Autofac نمی توانند از آن جلوگیری کنند.
اما IOC Container پیشفرض Asp.Net Core سعی کرده است تا حدی از این مشکل جلوگیری کند.
🔸 فعال سازی این ویژگی برای IOC Container پیشفرض اختیاری بوده و در صورت فعال سازی آن، نکته ای که باعث بهبود performance میشود این است که فقط در محیط و هنگام Development از آن استفاده کنید.
🔻همچنین باید بدانید که این ویژگی فقط از بروز Captive Dependency برای سرویس هایی که به صورت Scoped رجیستر شده اند، جلوگیری میکند و باعث صادر شدن استثنای InvalidOperationException میشود. و برای سرویس های که به صورت Transient رجیستر شده اند کار نمیکند.
❇️ برای فعال سازی این ویژگی در کلاس Program بدین شکل عمل کنید.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseDefaultServiceProvider((env, c) =>
{
if (env.HostingEnvironment.IsDevelopment())
{
c.ValidateScopes = true;
}
});
}
@FullStackDevs
Forwarded from Web Devs
#DI
#Ioc
#DIP
#SOLID
✳️ Captive Dependency
🔹 در این پست به توضیح مشکلی میپردازیم که معمولا به دلیل اشتباه کانفیگ کردن سرویس های اپلیکیشن در IOC Container رخ میدهد.
🔸 تزریق وابستگی (Dependency Injection) از مفاهیم مهمی هست که باید به آن آشنا باشیم. برای استفاده از این مفهوم و مفاهیم مرتبط با آن مثل IOC ,DIP
در اپلیکیشن، ابزار ها یا فریم وورک هایی وجود دارند که به آنها IOC Container می گوییم.
🔻اگر با DI و IOC و DIP آشنا نیستید مقالات لینک شده را مطالعه کنید.
🔸مدیریت lifeTime سرویس های اپلیکیشن امری است که به کمک IOC Container مقدر میشود اما وظیفه register کردن و معرفی کردن وابستگی ها به IOC Container بر عهده Developer میباشد.
🔸 اشتباه کانفیگ کردن lifeTime برای سرویسی در اپلیکیشن، که خود دارای وابستگی هایی، با lifeTime ای کمتر از lifeTime سرویس اصلی هستند، باعث به وجود آمد مشکل Captive Dependency میشود.
🔹 برای درک مسئله به مثال زیر توجه کنید
فرض کنید دو کلاس با نام های
ScopedDependency
SingletonDependency
داریم.
🔸 همانطور که از نام ها مشخص است کلاس SingletonDependency به صورت Singleton به DI Contaner معرفی شده و در طول عمر اپلیکیشن فقط یک نمونه از آن ساخته میشود.
🔸 کلاس ScopedDependency هم به صورت Scoped در IOC Container معرفی شده و به ازای هر connection به سرور فقط یک نمونه از آن به ازای هر کانکشن و درخواست ساخته میشود.
🔸 بیایید فرض کنیم که چه اتفاقی می افتد اگر کلاس SingletonDependency برای انجام برخی کارها در درون خود به کلاس ScopedDependency وابسته باشد و ما نیاز داشته باشیم که کلاس ScopedDependency در درون آن تزریق کنیم.
🔹 با رجیستر کردن کلاس ScopedDependency بصورت Scoped انتظار این است که روند نمونه سازی از این کلاس Scoped گونه باشد. اما وقتی این کلاس را در یک کلاس دیگر که به صورت Singleton رجیستر شده است تزریق میکنید، قوائد بازی را برهم زده و باعث میشوید که کلاس Singleton مورد نظر در تمام طول عمر خود فقط از یک نمونه قدیمی از وابستگی خود استفاده کند. این نمونه قدیمی برای اولین بار در هنگام ساخته شدن کلاس Singleton ای که در درون آن وجود دارد ساخته شده و به زندگی خود به لطف حضور در یک کلاس Singleton ادامه میدهد.
پس در نتیجه برای SingletonDepedency ما فقط یک نمونه از ScopedDependency ساخته میشود و در تمام طول عر خود از همان نمونه قدیمی استفاده میکند.
🔸در نگاه اول شاید این مشکل حاد به نظر نرسد اما باید بدانید که در یک پروژه که پیچیدگی های خاص خود را دارد باعث بروز مشکلات و باگ های فاحش خواهد شد.
🔸 این مشکل توسط Developer با اشتباه کانفیگ کردن lifeTime برای سرویس های اپلیکیشن رخ میدهد و حتی IOC Container هایی مانند Autofac نمی توانند از آن جلوگیری کنند.
اما IOC Container پیشفرض Asp.Net Core سعی کرده است تا حدی از این مشکل جلوگیری کند.
🔸 فعال سازی این ویژگی برای IOC Container پیشفرض اختیاری بوده و در صورت فعال سازی آن، نکته ای که باعث بهبود performance میشود این است که فقط در محیط و هنگام Development از آن استفاده کنید.
🔻همچنین باید بدانید که این ویژگی فقط از بروز Captive Dependency برای سرویس هایی که به صورت Scoped رجیستر شده اند، جلوگیری میکند و باعث صادر شدن استثنای InvalidOperationException میشود. و برای سرویس های که به صورت Transient رجیستر شده اند کار نمیکند.
❇️ برای فعال سازی این ویژگی در کلاس Program بدین شکل عمل کنید.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseDefaultServiceProvider((env, c) =>
{
if (env.HostingEnvironment.IsDevelopment())
{
c.ValidateScopes = true;
}
});
}
@FullStackDevs
#Ioc
#DIP
#SOLID
✳️ Captive Dependency
🔹 در این پست به توضیح مشکلی میپردازیم که معمولا به دلیل اشتباه کانفیگ کردن سرویس های اپلیکیشن در IOC Container رخ میدهد.
🔸 تزریق وابستگی (Dependency Injection) از مفاهیم مهمی هست که باید به آن آشنا باشیم. برای استفاده از این مفهوم و مفاهیم مرتبط با آن مثل IOC ,DIP
در اپلیکیشن، ابزار ها یا فریم وورک هایی وجود دارند که به آنها IOC Container می گوییم.
🔻اگر با DI و IOC و DIP آشنا نیستید مقالات لینک شده را مطالعه کنید.
🔸مدیریت lifeTime سرویس های اپلیکیشن امری است که به کمک IOC Container مقدر میشود اما وظیفه register کردن و معرفی کردن وابستگی ها به IOC Container بر عهده Developer میباشد.
🔸 اشتباه کانفیگ کردن lifeTime برای سرویسی در اپلیکیشن، که خود دارای وابستگی هایی، با lifeTime ای کمتر از lifeTime سرویس اصلی هستند، باعث به وجود آمد مشکل Captive Dependency میشود.
🔹 برای درک مسئله به مثال زیر توجه کنید
فرض کنید دو کلاس با نام های
ScopedDependency
SingletonDependency
داریم.
🔸 همانطور که از نام ها مشخص است کلاس SingletonDependency به صورت Singleton به DI Contaner معرفی شده و در طول عمر اپلیکیشن فقط یک نمونه از آن ساخته میشود.
🔸 کلاس ScopedDependency هم به صورت Scoped در IOC Container معرفی شده و به ازای هر connection به سرور فقط یک نمونه از آن به ازای هر کانکشن و درخواست ساخته میشود.
🔸 بیایید فرض کنیم که چه اتفاقی می افتد اگر کلاس SingletonDependency برای انجام برخی کارها در درون خود به کلاس ScopedDependency وابسته باشد و ما نیاز داشته باشیم که کلاس ScopedDependency در درون آن تزریق کنیم.
🔹 با رجیستر کردن کلاس ScopedDependency بصورت Scoped انتظار این است که روند نمونه سازی از این کلاس Scoped گونه باشد. اما وقتی این کلاس را در یک کلاس دیگر که به صورت Singleton رجیستر شده است تزریق میکنید، قوائد بازی را برهم زده و باعث میشوید که کلاس Singleton مورد نظر در تمام طول عمر خود فقط از یک نمونه قدیمی از وابستگی خود استفاده کند. این نمونه قدیمی برای اولین بار در هنگام ساخته شدن کلاس Singleton ای که در درون آن وجود دارد ساخته شده و به زندگی خود به لطف حضور در یک کلاس Singleton ادامه میدهد.
پس در نتیجه برای SingletonDepedency ما فقط یک نمونه از ScopedDependency ساخته میشود و در تمام طول عر خود از همان نمونه قدیمی استفاده میکند.
🔸در نگاه اول شاید این مشکل حاد به نظر نرسد اما باید بدانید که در یک پروژه که پیچیدگی های خاص خود را دارد باعث بروز مشکلات و باگ های فاحش خواهد شد.
🔸 این مشکل توسط Developer با اشتباه کانفیگ کردن lifeTime برای سرویس های اپلیکیشن رخ میدهد و حتی IOC Container هایی مانند Autofac نمی توانند از آن جلوگیری کنند.
اما IOC Container پیشفرض Asp.Net Core سعی کرده است تا حدی از این مشکل جلوگیری کند.
🔸 فعال سازی این ویژگی برای IOC Container پیشفرض اختیاری بوده و در صورت فعال سازی آن، نکته ای که باعث بهبود performance میشود این است که فقط در محیط و هنگام Development از آن استفاده کنید.
🔻همچنین باید بدانید که این ویژگی فقط از بروز Captive Dependency برای سرویس هایی که به صورت Scoped رجیستر شده اند، جلوگیری میکند و باعث صادر شدن استثنای InvalidOperationException میشود. و برای سرویس های که به صورت Transient رجیستر شده اند کار نمیکند.
❇️ برای فعال سازی این ویژگی در کلاس Program بدین شکل عمل کنید.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseDefaultServiceProvider((env, c) =>
{
if (env.HostingEnvironment.IsDevelopment())
{
c.ValidateScopes = true;
}
});
}
@FullStackDevs