ستحتاج لفيجوال ستديو 2012 او 2013 او 2015 او 2017 لتطبيق المثال الذي سنشرحه هنا.
ولقد قمت بإستخدام Visual Studio 2013 Express For Web لتطبيق تلك المكتبة.
لو فرضنا لدينا فئة class لحفظ تفاصيل درجة الحرارة C1 ولدى فئة أخري C2 لحساب درجات الحرارة وتعتمد على C1 وتلك الفئات قمت بإستدعائها من الـ Controller الخاصة بالمشروع الذي يوضح درجات الحرارة.
الآن لو لاحظنا الـ controller تعتمد على فئتين وهذا يعني أي تعديل في تلك الفئات يعني ان اقوم بعمل تعديل على الـ Controller وأيضا أيّ تعديل على الفئة C1 يعني أن اقوم بعمل تعديل على الـ C2 هذا التداخل يطلق عليه الاعتمادية أو ما يعرف بالـ Dependency ولحل هذه المشكلة يوجد العديد من المكتبات التي تساعدنا على فصل الفئات عن بعضها. ويمكننا ايضا فصل الفئات من دون استخدام تلك المكتبات لكن المكتبات ستسهل علينا العمل بسرعة وستقوم بعمل اشياء كثيرة اثناء عمل التطبيق. ويطلق على تلك المكتبات DI container
سنقوم بعمل تطبيق بسيط جدا يظهر لنا رسالة تهنئة بالعيد ويمكنك استخدام تلك الطريقة حتى على المشاريع الكبيرة والضخمة.
حسنا لنبدأ قم بفتح الفيجوال ستديو..قم بعمل مشروع ويب جديد وقم باختيار ASP.NET Web Application حدد المسار الذي تريد ان تحفظ فيه المشروع وقم بإعطاء المشروع الاسم HappyEid واضغط OK ستفتح لك نافذة لإختيار نوع التطبيق قم إختيار Empty واسفل الشاشة اضغط على المربع الصغير لتحديد مشروع الـ MVC واضغط OK.
بعد ان يقوم الفيجوال ستديو بالانتهاء من تهيئة التطبيق اضغط على TOOLS في اعلى الشريط المساعد الخاص بالفيجوال واختار الـ Library Package Manager والتي ستظهر لك خيارات عدة إضغط على اول خيار Package Manager Console واكتب السطر التالي:
PM> Install-Package ninject -version 3.0.1.10
في هذه الخطوة قمنا يتنزيل مكتبة الـ ninject وهي المكتبة التي تساعدنا على فصل الفئات عن بعضها البعض بإستخدام الواجهات Interfaces
في ملف الـ Models الذي انشئه الفيجوال ستديو قم بإنشاء واجهة Interface جديدة واعطها الإسم IHappyEid وأنشئ بها Method واحدة على هذا النحو:
public interface IHappyEid { string GetMessage(); }
قم بإنشاء فئة class باسم HappyEid ودعها ترث من الـ Interface التي انشأناها سابقا على هذا النحو:
public class HappyEid : IHappyEid { public string GetMessage() { return "Hi there I want to say for you EID MUBARK"; } }
قم بإنشاء ملف واعطه الاسم Infrastrucuture وقم بإنشاء فئة Class داخل هذا الملف بإسم NinjectControllerFactory هذه الفئة مهتمتها إنشاء Instance في حال كان هنالك معامل Parameter للـ Request والكود الخاص بهذه الفئة على هذا النحو:
public class NinjectControllerFactory : DefaultControllerFactory { private IKernel _kernel; public NinjectControllerFactory(IKernel kernel) { this._kernel = kernel;} protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController)_kernel.Get(controllerType); } }
لا تنسي ان تستدعي فضاء الاسماء الخاص بالمكتبة كالتالي:
using Ninject;
والكود يعني اذا كان هناك أي طلب للـ Controller دع المهمة للـ Ninject بإنشاء الطلب من خلال النواة Kernel الخاصة بهذه المكتبة وسنقوم بتعريف استقبال الطلب لاحقا على ملف الـ Global.
الآن سنقوم بتهيئة الفئة Class الخاص بالتهنئة التي اريدها ان تظهر على الشاشة من خلال استدعاء الـ Method التي توجد بالـ Controller.
قم بإنشاء فئة جديدة Class داخل ملف الـ Infrastrucuture وقم بإعطائها الاسم NinjectDefaultBinding وهذه الفئة من اسمها توضح للـ Controller عندما اقوم بإستدعاء الإسلوب ( )GetMessage من الواجهة IHappyEid قم بعمل حقن Inject في الفئة HappyEid وإرجاع التنفيذ الخاص بهذا الإسلوب Method implementation.
الان داخل الفئة NinjectDefaultBinding قم بكتابة الكود التالي:
public class NinjectDefaultBindings : NinjectModule { public override void Load() { Bind<IHappyEid>().To<HappyEid>(); } }
:لا تنسى ان تقوم بإستدعاء فضاء الاسماء التالي في اعلى الفئة
using Ninject; using Ninject.Modules; using HappyEid.Models;
دعنا نشرح هذه الفئة … الفئة ترث من فئة اخرى واسمها NinjectModule هذه الفئة بها العديد من الأساليب Load وهذه الفئة من النوع abstract وتعني اننا لا نستطيع ان ننشئ مثيل لها داخل الـ Manage heap من خلال المكدس Stack بإستخدام الكلمة new لذلك سنقوم بالكتابة فوقها override.
حسنا الـ Method تعني قم بإستدعاء الفئة في حال تم طلبها من خلال النواة
حسنا الخطوة الأخيرة في التهيئة سنقوم بتعريف الفئة NinjectDefaultBinding داخل النواة الخاصة بالـ ninject وهي الفئة Standardkernel والتي بدورها ترث من الـ kernelBase. وتقبل معامل Parameter من النوع INinjectModule وفي حالتنا هذه سيكون المعامل الخاص بنا هو NinjectDefaultBindings
قم بإنشاء فئة Class داخل ملف الـ Infrastructure واعطها الاسم NinjectBootStraper وقم بكتابة الكود التالي داخلها:
public static class NinjectBootStrapper { public static IKernel Kernel { get; private set; } public static void Initialize() { Kernel = new StandardKernel(new NinjectDefaultBindings()); } }
الآن سنقوم بإنشاء الـ Controller قم بإنشاء HomeController وقم بإختيار الخيار الفارغ Empty داخل هذا الفئة قم بكتابة التالي:
public class HomeController : Controller { private IHappyEid _provider; public HomeController(IHappyEid provider) { this._provider = provider; } // GET: GetHappyEidMessage public string GetHappyEidMessage() { return _provider.GetMessage(); } }
لا تنسى استدعاء فضاء الاسماء
using HappyEid.Models;
قم بكتابة الكود التالي داخل ملف الـ Global داخل الـ Method التالية Application_Start()
NinjectBootStrapper.Initialize(); ControllerBuilder.Current.SetControllerFactory( new NinjectControllerFactory(NinjectBootStrapper.Kernel));
أيضا هنا قم بإستدعاء فضاء الاسماء
using HappyEid.Infrastrucuture;
في الـ Controller قمنا بإستخدام الواجهات وكما شرحت في الفئة NinjectModule بأننا لا نحتاج بأن ننشئ مثيل للـ Controller من خلال الـ Default constructor بل سندع المهمة للـ Ninject.
** قد يكون في المشاريع الصغيرة لن تحس بصعوبة في التعديل عندما تحتاج لتعديل بعض الفئات… لكن من واقع خبرتنا العملية في مشاريع ضخمة قد تكون لم تعمل على مشاريع مثلها ستحتاج لتلك المكتبة..او ستحتاج لتطبيق مبدأ الـ IOC.
الآن قم بتجربة التطبيق على المتصفح لديك بكتابة الرابط التالي على عنوان الوصول في متصفحك
http://localhost:1116/Home/GetHappyEidMessage البورت سيكون مختلفا…
سترى الرسالة التالية على المتصفح
Hi there I want to say for you EID MUBARK
:هل تدري ان الثلاثة فئات تلك
NinjectControllerFactory NinjectDefaultBindings NinjectBootStrapper
هل تدري ان تلك الفئات يمكننا كتابتها في فئة واحدة؟ لكن لماذا قمت بكتابتها لكم بتلك الصورة؟ قم بتهيئتها بتلك الصورة لي يكتمل لديكم فهمها جيدا بحيث تعرف ماهي مهمة كل فئة… حسنا اذا كنت تريد كتابتها في فئة واحدة قم بعمل التالي
داخل ملف الـ Infrastructure قم بإنشاء الفئة NinjectControllerFactory
ودعها ترث من الفئة DefaultControllerFactory وقم بكتابة الكود التالي:
public class NinjectControllerFactory : DefaultControllerFactory { private IKernel _kernel; public NinjectControllerFactory(IKernel kernel) { this._kernel = kernel; NinjectDefaultBindings(); } protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController)_kernel.Get(controllerType); /*if (controllerType == null) { return null; } else { return (IController)_kernel.Get(controllerType); }*/ } private void NinjectDefaultBindings() { _kernel.Bind<IHappyEid>().To<HappyEid>(); } }
ولا تنسى ان تعدل ملف الـ Global ليصبح كالتالي:
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactor());
لاحظ لقد قمت بشرح طريقة انشاء مثيل من الـ Controller في نفس الكود بكتابة الكود نفسه بطريقة جملة if والشفرتين يمكنهما العمل ، لكن لقد قمت بعمل Comment على الجملة الشرطية…وفي حال ان اردت ان تعمل بالجملة الشرطية قم بعمل Comment على السطر المبسط الذي يستخدم تقنية الـ #C للتأكد من عدم فراغ العنصر.
*** الطريقة الأولى التي تفصل الفئات عن بعضها (الثلاثة فئات) تعتبر أفضل لأنها تبيّن لك مهمة كل فئة…لكن يمكنك ان تعمل ايضا على الطريقة الثانية إن أردت.
*** أيضا بإمكانك إضافة الفئات وحقن الواجهات Interfaces داخل الإسلوب Method التي قمنا بتعريفها على هذا النحو:
private void NinjectDefaultBindings() { _kernel.Bind<IHappyEid>().To<HappyEid>(); }
*** هنالك العديد من المكتبات الأخرى في حال لم ترد إستخدام مكتبة الـ Ninject فبإمكانك البحث عنها ومعرفة طريقة عملها.