Dependency Inject Using Ninject IoC In Console Application

Introduction

This article introduces how to use dependency injection in a console application with the help of Ninject container. Dependency Injection (DI) is a pattern where objects are not responsible for creating their own dependencies. It is a way to remove hard-coded dependencies among objects, making it easier to replace an object's dependencies, either for testing (using mock objects in unit test) or to change run-time behavior.

Before understanding Dependency Injection, you should be familiar with the two concepts of Object Oriented Programming, Tight Coupling and Loose Coupling. So, let's see each, one by one.

  • Tight Coupling
    When a class is dependent on a concrete dependency, it is said to be tightly coupled to that class. A tightly coupled object is dependent on another object; that means, changing one object in a tightly coupled application often requires changes to a number of other objects. It is not difficult when an application is small, but in an enterprise level application, it is too difficult to make the changes.

  • Loose Coupling
    It means two objects are independent and an object can use another object without being dependent on it. It is a design goal that seeks to reduce the inter- dependencies among components of a system, with the goal of reducing the risk that changes in one component will require changes in any other component. 
Now, in short, Dependency Injection is a pattern that makes objects loosely coupled instead of tightly coupled. Generally, we create a concrete class object in the class where we require the object, and bind it in the dependent class. But, DI is a pattern where we create a concrete class object outside this high-level module or dependent class.

There are three types of Dependency Injections:
  1. Constructor Dependency Injection
  2. Setter Dependency Injection
  3. Interface Dependency Injection

Dependency Injection (DI) Container

The Dependency Injection Container is a framework to create dependencies and inject them automatically when required. It automatically creates objects based on requests, and injects them when required. It helps us split our application into a collection of loosely-coupled, highly-cohesive pieces, and then, glue them back together in a flexible manner. By DI container, our code will become easier to write, reuse, test, and modify. In this article, we will use a Niject DI Container.

Using the Code

We create a sample console application in C#, using Visual Studio 2015. This application has the following features.

  • The Ninject IoC is used to implement Dependency Injection.
  • Creating a generic repository for inserting the collection of entities in database.
  • Read data from JSON file and deserialize JSON data to entity/entities.
  • Database first approach is used to perform the insert operation.
  • With Dispose pattern.

First of all, we create a table Employee in the database, using the following script.

  1. Create Table Employee  
  2. (  
  3. EmployeeId bigint identity(1,1) primary key,  
  4. FirstName nvarchar(50),  
  5. LastName nvarchar(50),  
  6. Email nvarchar(100)  
  7. )  
We create four projects in the solution, as follow. 
  • DIConsole: A console application which runs. It has integration of IoC(Ninject).
  • DI.Data: It’s a class library which has edmx file where the database table is mapped.
  • DI.Repo: It’s class library that performs insert operation for entity.
  • DI.Service: It’s class library that communicates to console application by interface.

The communication flow among these projects is shown in the following figure.

Operation work flow
Figure 1: Operation work flow

We install Entity Framework using nuGet package, as shown in following figure 2.

 Install Entity Framework by nuget package
Figure 2: Install Entity Framework by nuGet package

We create edmx file and map database’s tables in it.

Entity in edmx file
Figure 3: Entity in edmx file

Now, we create IRepository interface in DI.Repo project. It has two method signatures-  First one is InsertCollection which is used to insert Entity Collection and another one is the Dispose method signature. The following is the code snippet for the same.

  1. using System.Collections.Generic;  
  2.   
  3. namespace DI.Repo  
  4. {  
  5.     public interface IRepository<TEntity> where TEntity : class  
  6.     {  
  7.         void InsertCollection(List<TEntity> entityCollection);  
  8.         void Dispose();  
  9.     }  
  10. }  
After that, we create Repository class in the same project that has implementation of IRepository interface, as per the following code snippet.
  1. using DI.Data;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Data.Entity;  
  5. using System.Data.Entity.Validation;  
  6. using System.Text;  
  7.   
  8. namespace DI.Repo  
  9. {  
  10.     public class Repository<TEntity> : IRepository<TEntity> where TEntity : class  
  11.     {  
  12.         internal DIConsoleEntities context;  
  13.         internal IDbSet<TEntity> dbSet;  
  14.   
  15.         public Repository(DIConsoleEntities context)  
  16.         {  
  17.             this.context = context;  
  18.             this.dbSet = context.Set<TEntity>();  
  19.         }  
  20.   
  21.         public void InsertCollection(List<TEntity> entityCollection)  
  22.         {  
  23.             try  
  24.             {  
  25.                 entityCollection.ForEach(e =>  
  26.                 {  
  27.                     dbSet.Add(e);  
  28.                 });                 
  29.                 context.SaveChanges();  
  30.             }  
  31.             catch (DbEntityValidationException ex)  
  32.             {  
  33.                 StringBuilder sb = new StringBuilder();  
  34.   
  35.                 foreach (var failure in ex.EntityValidationErrors)  
  36.                 {  
  37.                     sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());  
  38.                     foreach (var error in failure.ValidationErrors)  
  39.                     {  
  40.                         sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);  
  41.                         sb.AppendLine();  
  42.                     }  
  43.                 }  
  44.   
  45.                 throw new DbEntityValidationException(  
  46.                     "Entity Validation Failed - errors follow:\n" +  
  47.                     sb.ToString(), ex  
  48.                 );  
  49.             }  
  50.         }  
  51.   
  52.         public void Dispose()  
  53.         {  
  54.             GC.SuppressFinalize(this);  
  55.         }  
  56.     }  
  57. }  
We create IEmployeeService in DI.Service project which communicates to the console application. The following is the code snippet for the same.
  1. using DI.Data;  
  2. using System;  
  3. using System.Collections.Generic;  
  4.   
  5. namespace DI.Service  
  6. {  
  7.     public interface IEmployeeService : IDisposable  
  8.     {  
  9.         List<Employee> InsertEmployee(List<Employee> employees);  
  10.     }  
  11. }  
We implement the above interface in EmployeeService class in same project, as shown in following code snippet.
  1. using System.Collections.Generic;  
  2. using DI.Data;  
  3. using DI.Repo;  
  4.   
  5. namespace DI.Service  
  6. {  
  7.     public class EmployeeService : IEmployeeService  
  8.     {  
  9.         private readonly IRepository<Employee> repoEmployee;  
  10.   
  11.         public EmployeeService(IRepository<Employee> repoEmployee)  
  12.         {  
  13.             this.repoEmployee = repoEmployee;  
  14.         }  
  15.   
  16.         public List<Employee> InsertEmployee(List<Employee> employees)  
  17.         {  
  18.             repoEmployee.InsertCollection(employees);  
  19.             return employees;  
  20.         }  
  21.   
  22.         private bool disposedValue = false;  
  23.   
  24.         protected virtual void Dispose(bool disposing)  
  25.         {  
  26.             if (!disposedValue)  
  27.             {  
  28.                 if (disposing)  
  29.                 {  
  30.                     repoEmployee.Dispose();  
  31.                 }  
  32.                 disposedValue = true;  
  33.             }  
  34.         }  
  35.   
  36.         public void Dispose()  
  37.         {  
  38.             Dispose(true);  
  39.         }  
  40.     }  
  41. }  
Now, we work in DIConsole project in which we install Ninject by nuGet package, using Package Manager Console window. We run the following command to install it.

PM> Install-Package Ninject -Version 3.2.2

After that, we install Newtonsoft JSON by nuGet package, using Package Manager Console window. We run the following command to install it.

PM>Install-Package Newtonsoft.Json

We register repository and context class in Ninject module which helps in creating the instance of these classes. The following class is added in DIConsole project.
  1. using DI.Repo;  
  2. using Ninject.Modules;  
  3. using System;  
  4.   
  5. namespace DIConsole  
  6. {  
  7.     public class EmployeeExportModule:NinjectModule  
  8.     {  
  9.         public override void Load()  
  10.         {  
  11.             Bind(Type.GetType("DI.Data.DIConsoleEntities, DI.Data")).ToSelf().InSingletonScope();  
  12.             Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope();  
  13.         }  
  14.     }  
  15. }  
We create an operation class which calls insert method of employee service. Here, we use IEmployeeService instance created by Dependency Injection. This class has a LoadEmployeeJson method which reads data from JSON file and deserialize the data in the Employee collection.
  1. using DI.Data;  
  2. using DI.Service;  
  3. using Newtonsoft.Json;  
  4. using Ninject;  
  5. using System;  
  6. using System.Collections.Generic;  
  7. using System.IO;  
  8.   
  9. namespace DIConsole  
  10. {  
  11.     public class EmployeeExportOperation :IDisposable  
  12.     {  
  13.         private readonly IEmployeeService employeeService;  
  14.   
  15.         public EmployeeExportOperation(IKernel kernel)  
  16.         {  
  17.             employeeService = kernel.Get<EmployeeService>();  
  18.         }  
  19.   
  20.         public void SaveEmployee()  
  21.         {  
  22.             List<Employee> employees = LoadEmployeeJson();  
  23.             employeeService.InsertEmployee(employees);  
  24.         }  
  25.         private List<Employee> LoadEmployeeJson()  
  26.         {  
  27.             using (StreamReader streamReader = new StreamReader("employee.json"))  
  28.             {  
  29.                 string json = streamReader.ReadToEnd();  
  30.                 List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json);  
  31.                 return employees;  
  32.             }  
  33.         }  
  34.         private bool disposedValue = false;   
  35.   
  36.         protected virtual void Dispose(bool disposing)  
  37.         {  
  38.             if (!disposedValue)  
  39.             {  
  40.                 if (disposing)  
  41.                 {  
  42.                     employeeService.Dispose();  
  43.                 }  
  44.                 disposedValue = true;  
  45.             }  
  46.         }  
  47.   
  48.         public void Dispose()  
  49.         {              
  50.             Dispose(true);             
  51.         }   
  52.     }  
  53. }  
Now, we update Main method of the program class to call saveEmployee method of EmployeeExportOpertion, as per the following code snippet.
  1. using Ninject;  
  2.   
  3. namespace DIConsole  
  4. {  
  5.     class Program  
  6.     {  
  7.         static void Main(string[] args)  
  8.         {  
  9.             IKernel kernal = new StandardKernel(new EmployeeExportModule());  
  10.             EmployeeExportOperation employeeExportOperation = new EmployeeExportOperation(kernal);  
  11.             employeeExportOperation.SaveEmployee();  
  12.             System.Console.ReadKey();  
  13.         }  
  14.     }  
  15. }  
Now, run the application and the result displays as per the following figure.

Result of application
Figure 4: Result of application

Download

You can download the complete solution source code from this link.

Other Resources

There are some other resources for implementation of dependency injection, as follow. 

Next Recommended Readings