تزریق وابستگی با استفاده از Ninject IoC در Console Application
سه شنبه 16 شهریور 1395در این مقاله نحوه استفاده از تزریق وابستگی در Console Application را با کمک Ninject IoC خواهیم آموخت. Dependency Injection الگویی است که بیان دارد ، object ها مسئولیتی در قبال ساختن وابستگی هایشان (dependencies) ندارند. این روش یک راه برای حذف کدهای-سخت (hard-coded) وابستگی ها، از Object است، و برای جابجا کردن وابستگی های یک Object ، همچنین برای تست کردن و عوض کردن رفتار های run-time کار را راحت می کند .
قبل از فهمیدن Dependency Injection ، این امر نیاز است که شما با دو مورد از ویزگی های برنامه نویسی شی گرا (OOP) آشنا باشید ، Tight Coupling و Loose Coupling . ما در این جا مرحله به مرحله به آنها خواهیم پرداخت .
• Tight Coupling :
هنگامی که یک کلاس ، وابسته به یک وابستگی واقعی (concrete dependency) است ، در اینجاست که گفته می شود ، کلاس محکم پیوسته (Tight Coupled) است . یک شی Tight Coupled به اشیا دیگر وابسته است . بدین معنی که ، که در یک برنامه Tight Coupled در صورت تغییر یک شی ، معمولا نیاز است که اشیاء دیگر نیز تغییر کند . وقتی برنامه ی ما کوچک است ، این امر زیاد مشکل نیست ، اما در یک برنامه در حد یک شرکت ، این امر بسیار مشکل است که تغییراتی را ایجاد کنیم .
• Loose Coupling
این بدان معناست که دو تا شی از یکدیگر مستقل هستند و یک شی بدون اینکه وابسته به شی ای باشد میتواند از آن شی استفاده کند . هدف از این طراحی کاهش وابستگی بین عناصر یک سیستم است برای اینکه با تغییر یکی از عناصر برنامه نیازی به تغییر دیگر عناصر برنامه نباشد .
حال اگر ، بطور مختصر بخواهیم توضیح دهیم ، Dependency Injection الگویی است که اشیاء را تبدیل به loosely coupled میکند . در حالت کلی ، ما شی ای از یک کلاس را در جایی میسازیم که به آن شی نیاز داریم ، و از آن در کلاس های مرتبط استفاده میکنیم . اما ، DI یک الگویی است که با کمک آن ما یک شی از یک کلاس را خارج از ماژول های سطح بالا یا کلاس های مرتبط به آن ، میسازیم .
سه نوع از تزریق وابستگی :
1. Constructor Dependency Injection
2. Setter Dependency Injection
3. Interface Dependency Injection
Dependency Injection (DI) Container
Dependency Injection (DI) Container یک کتابخانه (framework) برای ساختن وابستگی ها و استفاده از آنها در زمان درخواست ، است . این ، بصورت خودکار اشیاء را بر مبنای تقاضاها میسازد ، و زمانی که نیاز است از آنها استفاده می کند . و به ما کمک می کند ، که برنامه خود را به مجموعه از قسمت های loosely-coupled و منسجم (highly-cohesive) تقسیم کرده ، و سپس آنها را بطور خیلی انعطاف پذیر با هم ادغام کنیم . توسط DI Container ، نوشتن کد (write code) ، تست کردن (test) و توسعه (modify) و استفاده چند باره (reuse) از برنامه ما راحت تر میشود . در این مقاله ما از Ninject DI Container استفاده خواهیم کرد.
استفاده از Code :
در Visual Sudio 2015 ، یک پروژه Console Application میسازیم ، پروژه ما ویژگی های زیر را خواهد داشت :
• برای پیاده سازی Dependency Injection از Ninject IoC استفاده شده است .
• برای وارد کردن Entity ها در پایگاه داده یک generic repository بسازید .
• اطلاعات را از فایل JSON بخواند و داده ها را در deserialize ، Entity/Entities کند .
• برای انجام عملیات insert ، از Database First استفاده کردیم .
• الگوی دور ( With Dispose pattern )
اول از هر چیز ، با استفاده از Query های زیر جدول Employee را در پایگاه داده خود ایجاد می کنیم .
Create Table Employee ( EmployeeId bigint identity(1,1) primary key, FirstName nvarchar(50), LastName nvarchar(50), Email nvarchar(100) )
در Solution چهار پروژه خواهیم داشت :
• DIConsole : یک Console Applilcation که اجرا میشود . این با Ninject IoC همبستگی دارد .
• DI.Data : یک class library است ، که جداول پایگاه داده با فرمت edmx درآنجا وجود دارد .
• DI.Repo : یک class library است که عملیات insert را برای entityها انجام می دهد .
• DI.Service : یک class library است که با استفاده از Interface با Console Application در ارتباط است .
ارتباطات موجود در این پروژه را میتوانید در زیر مشاهده کنید :
شکل 1 : عملیات گردش کار
همانطور که در شکل 2 نمایش داده شده است ، با استفاده از NuGet Package ، کتابخانه Entity را نصب می کنیم .
شکل 2 : با استفاده از Nuget Packag ، کتابخانه Entity را نصب کنید .
فایل edmx را میسازیم و جداول پایگاه داده را در آن درج میکنیم .
شکل 3 : entity های موجود در فایل edmx
حال ، اینترفیس IRepository را در پروژه DI.Repo میسازیم . این دوتا Methode Signature دارد - اولی InsertCollection است که در insert کردن مجموعه entity ها استفاده میشود و دیگری Dispose method signature است . کدهای زیر را مشاهده کنید.
using System.Collections.Generic; namespace DI.Repo { public interface IRepository<TEntity> where TEntity : class { void InsertCollection(List<TEntity> entityCollection); void Dispose(); } }
بعد از آن ، در پروژه ای که اینترفیس IRepository را پیاده سازی کرده ایم ، یک کلاس Repository میسازیم .
using DI.Data; using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Validation; using System.Text; namespace DI.Repo { public class Repository<TEntity> : IRepository<TEntity> where TEntity : class { internal DIConsoleEntities context; internal IDbSet<TEntity> dbSet; public Repository(DIConsoleEntities context) { this.context = context; this.dbSet = context.Set<TEntity>(); } public void InsertCollection(List<TEntity> entityCollection) { try { entityCollection.ForEach(e => { dbSet.Add(e); }); context.SaveChanges(); } catch (DbEntityValidationException ex) { StringBuilder sb = new StringBuilder(); foreach (var failure in ex.EntityValidationErrors) { sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType()); foreach (var error in failure.ValidationErrors) { sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage); sb.AppendLine(); } } throw new DbEntityValidationException( "Entity Validation Failed - errors follow:\n" + sb.ToString(), ex ); } } public void Dispose() { GC.SuppressFinalize(this); } } }
IEmployeeService را در پروژه DI.Service ، برای ارتباط با Console Application میسازیم .
using DI.Data; using System; using System.Collections.Generic; namespace DI.Service { public interface IEmployeeService : IDisposable { List<Employee> InsertEmployee(List<Employee> employees); } }
interface بالا را در کلاس EmployeeService ، در همان پروژه پیاده سازی میکنیم .
using System.Collections.Generic; using DI.Data; using DI.Repo; namespace DI.Service { public class EmployeeService : IEmployeeService { private readonly IRepository<Employee> repoEmployee; public EmployeeService(IRepository<Employee> repoEmployee) { this.repoEmployee = repoEmployee; } public List<Employee> InsertEmployee(List<Employee> employees) { repoEmployee.InsertCollection(employees); return employees; } private bool disposedValue = false; protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { repoEmployee.Dispose(); } disposedValue = true; } } public void Dispose() { Dispose(true); } } }
حال ، با پروژه DIConsole کار خواهیم کرد که ما در آن Ninject را بوسیله NuGet package نصب خواهیم کرد . از Package Manager Console window استفاده میکنیم . برای نصب کد زیر را اجرا کنید .
PM> Install-Package Ninject -Version 3.2.2
بعد از آن باید Newtonsoft JSON را نصب کنیم . کد زیر را اجرا کنید .
PM>Install-Package Newtonsoft.Json
در ماژول Ninject کلاس context و repository را ثبت می کنیم که همین امر ما را در ساختن نمونه ای (instance) از کلاس کمک میکند . کلاس زیر به پروژه DIConsole اضافه خواهد شد .
using DI.Repo; using Ninject.Modules; using System; namespace DIConsole { public class EmployeeExportModule:NinjectModule { public override void Load() { Bind(Type.GetType("DI.Data.DIConsoleEntities, DI.Data")).ToSelf().InSingletonScope(); Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope(); } } }
یک کلاس عملیاتی (opration class) برای فراخوانی متد insert از سرویس employee ، میسازیم . در اینجا ، ما از نمونه ای که توسط DI برای IEmployeeService ساخته شده است ، استفاده خواهیم کرد .
این کلاس یک متد با نام LoadEmployeeJson دارد که وظیفه خواندن اطلاعات از فایل JSON و deserialize کردن داده ها در مجموعه Employee را دارد .
using DI.Data; using DI.Service; using Newtonsoft.Json; using Ninject; using System; using System.Collections.Generic; using System.IO; namespace DIConsole { public class EmployeeExportOperation :IDisposable { private readonly IEmployeeService employeeService; public EmployeeExportOperation(IKernel kernel) { employeeService = kernel.Get<EmployeeService>(); } public void SaveEmployee() { List<Employee> employees = LoadEmployeeJson(); employeeService.InsertEmployee(employees); } private List<Employee> LoadEmployeeJson() { using (StreamReader streamReader = new StreamReader("employee.json")) { string json = streamReader.ReadToEnd(); List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json); return employees; } } private bool disposedValue = false; protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { employeeService.Dispose(); } disposedValue = true; } } public void Dispose() { Dispose(true); } } }
حال ، متد Main از کلاس Program را برای فراخوانی متد saveEmployee از EmployeeExportOpertion را بروزرسانی می کنیم .
using Ninject; namespace DIConsole { class Program { static void Main(string[] args) { IKernel kernal = new StandardKernel(new EmployeeExportModule()); EmployeeExportOperation employeeExportOperation = new EmployeeExportOperation(kernal); employeeExportOperation.SaveEmployee(); System.Console.ReadKey(); } } }
حال برنامه را اجرا میکنیم و خروجی را میبینیم .
آموزش سی شارپ
- C#.net
- 2k بازدید
- 1 تشکر