Share via


C#: Dependency Injection In Console Application

Introduction

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 Ninject 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 a 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 an edmx file where the database table is mapped.
  • DI.Repo: It's a class library that performs insert operation for the entity.
  • DI.Service: It's a class library that communicates to console application by the 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 an 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 the 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 a DIConsole project in which we install Ninject by a 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 a 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 the 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 the Main method of the program class to call the saveEmployee method of EmployeeExportOpertion, as per the following code snippet.

using Ninject;  
   
namespace DIConsole  
{  
    class Program  
    {  
        static void  Main(string[] args)  
        {  
            IKernel kernel = new  StandardKernel(new EmployeeExportModule());  
            EmployeeExportOperation employeeExportOperation = new  EmployeeExportOperation(kernel);  
            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 https://code.msdn.microsoft.com/Dependency-Injection-in-e7adb082

See Also

There are some more article related C#. These are:

  1. C# 7 : Func, Action And Local Function
  2. C# 7 : Tuple
  3. C# : Why Use Property