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:
- Constructor Dependency Injection
- Setter Dependency Injection
- 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.
- Create Table Employee
- (
- EmployeeId bigint identity(1,1) primary key,
- FirstName nvarchar(50),
- LastName nvarchar(50),
- Email nvarchar(100)
- )
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.
Figure 1: Operation work flow
We install Entity Framework using nuGet package, as shown in following figure 2.
Figure 2: Install Entity Framework by nuGet package
We create edmx file and map database’s tables in it.
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.
- using System.Collections.Generic;
-
- namespace DI.Repo
- {
- public interface IRepository<TEntity> where TEntity : class
- {
- void InsertCollection(List<TEntity> entityCollection);
- void Dispose();
- }
- }
After that, we create Repository class in the same project that has implementation of IRepository interface, as per the following code snippet.
- 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);
- }
- }
- }
We create IEmployeeService in DI.Service project which communicates to the console application. The following is the code snippet for the same.
- using DI.Data;
- using System;
- using System.Collections.Generic;
-
- namespace DI.Service
- {
- public interface IEmployeeService : IDisposable
- {
- List<Employee> InsertEmployee(List<Employee> employees);
- }
- }
We implement the above interface in EmployeeService class in same project, as shown in following code snippet.
- 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);
- }
- }
- }
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.
- 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();
- }
- }
- }
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.
- 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);
- }
- }
- }
Now, we update Main method of the program class to call saveEmployee method of EmployeeExportOpertion, as per the following code snippet.
- 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();
- }
- }
- }
Now, run the application and the result displays as per the following figure.
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.