Dependency Injection in C#

Dependency Injection

Simply, Dependency Injection means injecting any dependency to a module. Before discussing about Dependency Injection, let us start our discussion with Inversion of Control (IOC).

IOC principle says that “Don’t instantiate any class in a project if that class is not defined in that project.” Let us say we have two projects –

ProjectX – Contains classes A & B

ProjectY – Contains classes C & D

Consider ProjectX as web project and ProjectY is used to access database.

As per Inversion of Control principle, we cannot instantiate ProjectY classes (C &D) in the ProjectX. Then a big question is how do we access the databases then? The answer is using Dependency Injection.

Let us consider we have one MVC application Product Management App. Here we have two projects – one is web module and another one is DB Module. Web Module is dependent on DB module for any database related activities.

We are using Entity Framework in ProductDB to carryout DB related activities. The entity framework Code First Approach is used after defining two model classes Product and Reviews.

namespace ProductDB
{
    public class Product
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual int Stock { get; set; }
        public virtual string ManufacturingYear { get; set; }
        public virtual decimal Price { get; set; }
        public virtual ICollection<Review> Reviews { get; set; }
    }
}

namespace ProductDB
{
    public class Review
    {
        public virtual int Id { get; set; }
        public virtual string author { get; set; }
        public virtual string Comment { get; set; }
    }          
}

We have to develop one interface IProductDB, so that we will not directly use entity framework classes in Controller i.e. inside web project.

namespace ProductDB
{
    public interface IProductDB
    {
        IQueryable<Product> Products { get; }
        IQueryable<Review> Reviews { get; }
    }
}

Another class ProductDbContext is defined by inheriting EF DbContext class and implementing IProductDB interface.

namespace ProductDB
{
    public class ProductDbContext : DbContext, IProductDB
    {
        public ProductDbContext() 
            : base("ProductDBCon")
        {

        }

        public DbSet<Product> Products { get; set; }
        public DbSet<Review> Reviews { get; set; }

        IQueryable<Product> IProductDB.Products => Products;
        IQueryable<Review> IProductDB.Reviews => Reviews;
    }
}

Now, let’s go to our Web Project and define one basic action to fetch all the products –

Here we need to get all the products from database. As shown below we have defined one reference of IProductDB and in the controller, we are creating the object of the ProductDbContext and assigning it to the reference variable.

namespace ProductManagementApp.Controllers
{
    public class ProductController : Controller
    {
        private readonly IProductDB _dbContext;

        public ProductController()
        {
            _dbContext = new ProductDbContext();
        }

        // GET: Product
        public ActionResult Index()
        {
            var products = _dbContext.Products.ToList();
            return View(products);
        }
        
    }
}

Here the code will work and generate proper output but it’s having some design problems. If you notice, we are trying to create an instance of the class ProductDbContext. This is defined on DB layer inside Product Controller. As we are trying to create instance of a class defined in a seperate project, so it is violating IOC principle. The problem with this approach is given below,

In the future, if we want to change the DB layer from entity framework to normal ADO.NET or consider of migrating from SQL Server to Oracle, then we need to change the code of the Controller (Instead of ProductDbContext in SQL, we may have ProductOracleDbContext or something else). In real world scenario, we will have a considerable amount of change. Think, if the application is very much stable and is working fine since last 4/5 years, then changing all the controllers would trigger a significant amount of business cost (development, unit testing, SIT, UAT etc.).

So, what is the solution?

Use IOC principle and dependency injection to remove the hard dependency on ProductDbContext class in ProductController. Therefore, our product controller would be,

namespace ProductManagementApp.Controllers
{
    public class ProductController : Controller
    {
        private readonly IProductDB _dbContext;

        public ProductController(IProductDB dbContext)
        {
            _dbContext = dbContext;
        }

        // GET: Product
        public ActionResult Index()
        {
            var products = _dbContext.Products.ToList();
            return View(products);
        }
        
    }
}

Here we will receive a reference of the IProductDB in the constructor of the Product Controller. So, what are we expecting? Someone else will instantiate the ProductDbContext class and send a reference variable to the constructor of the Product Controller. Dependency Injection tools help us to achieve this.

There are several DI tools available like Unity, StructureMap etc.

Using Nuget Package Manager, we can download the package Unity.MVC5 and install it in our web application project. Once the installation is done, we can see Unity.config in the app start folder,

Open the file Unity.config and add the below highlighted line,

Open Global.asax and call the RegisterComponents method of the UnityConfig class,

That’s it. Now Unity will hook the event when controller will instantiate and will send the ProductDbContext object to the constructor of the controller.

 

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.