Hello All,
We will work on dependency injection in this article. We will go through every steps with easy example. At the end of the article you will be able to handle the DI without any issues.
Lets Start...
What is?
Basically Dependency Injection is the design pattern which helps developer to decouple the different pieces of their applications.
Just for Fun in coding : Consider I am going to trip, what I will do? First I will plan for the trip, Then I will take all the necessary things required for my trip and keep all the things in the bag, then will go to trip. While travelling! I will use the items from the bag and keep them back in the bag. In my case Bag is acting as container
In general word, It help us to create the application which loosely coupled, means every client no need to create the object instead they can request container(Which is used for DI) to provide the object of the required class.
If No Dependency Injection?
Lets say we have a class called Product we need to use in three pages, Product Detail, Featured Product and Top Product.
To Get the Product Detail in all three pages, we need to create the object of the Product Class in all three pages, which makes code complex
In case disposing, we need to do for all the pages, if we forget to do in any one of the page, then it will be a an issue.
In case any implementation changes, some time we need to do in all the pages, as we are dealing with inline stuffs.
Really Dependency Injection Helps Us:
We use container in Dependency Injection, and register all the dependencies used for the application.
We request container to provide the object of the class requested, instead creating the object.
In this way container takes whole responsibility of the object creation and disposing.
Dependency Inject is the 5th Principle of solid principle
What is IoC?
IoC is also called as Inversion of Control, It is a design pattern or principle suggests that the IoC of various types of controls in Object oriented design to achieve loose coupling between the application classes.
ASP .NET Core is designed from scratch so it supports dependency injection by default, because of this all the services in ASP .NET Core can be injected into your classes rather than being tightly coupled.
As we know ASP .NET Core has Built in IoC Container.
For legacy, there are a lot of excellent DI Containers that are available
- StructureMap
- Spring.NET
- Autofac
- Unity
- Ninject
The Inversion of Controller creates that objects and it sends it over to you in the constructor parameter.
The types of classes that are managed by Inversion of Container is called Services. We have two types of Services.
- Framework Services
- Application Services
The service that we build for our application.
Is There any life time for Services?
Yes, We have....
Basically Dependency Injection Life time is determined by when dependency is instantiated and how long it lives and dependency injection container is completely responsible for this.
In previous version of ASP .NET we had to use third party libraries such as Unity Container, niject etc.. But simple DI Container is built for ASP .NET Core and it does not require a lots of setup.
Can we use third party container?
If you want to us third party container like autofac, you can still use it, but usually the inbuilt dependency Injection Container is good enough for us.
There are three types of Service Lifetimes:
- Singleton
- Scoped
- Transient
1. Singleton:
In this same instance share for the life of the application, until we restart the application.
services.AddSingleTon<Interface, Implementor>();
Example:
If we click on all the views or link on a website, whenever instance is required it will send same object.
We should not forget this, In singleton pattern instance is kept in memory during the whole application lifetime, which will occupy the memory usage. But we have one plus point here i.e. in singleton memory will be allocated only one time, so garbage collector will have less work to do.
The easiest way to think of a single item is to have a static readable in a class. It is singleton even if two users hits our website, the code will still use the same instance.
2. Scoped:
We will have same instance for one scope, example if we create the objects of the class in one function multiple times, then same object will be send to the user.
services.AddScoped<Interface, Implementor>();
Its not best practice to use Scoped for multithreading, because it sends a new instance for each requests.
A good user for Scoped is EntitiFrameWork DbContext class, Here Scoped lifetime within a created scope object.
Final one is Transient....
3. Transient:
Always Sending New Instance Every request is Transient
If we request Product object 10 times, 10 times we will get different objects.
services.AddTransient<Interface, Implementor>();
Lets see with small program.
1. Create New Project "ASP.NET Core Web App(Model View Controller)"
2. Enter Project Name and Select Project Location Then Click Next
3. Here is the created project
4. Lets Create folder called Interfaces and Add three Interface files in it
5. Here is the Interface class and method declaration
namespace Dependency_Injection_Example.Interfaces { public interface IOperation { Guid OperationId { get; } } }
ITransientExample.cs
namespace Dependency_Injection_Example.Interfaces { public interface ITransientExample : IOperation { } }
IScopedExample.cs
namespace Dependency_Injection_Example.Interfaces { public interface IScopedExample : IOperation { } }
ISingleTonExample.cs
namespace Dependency_Injection_Example.Interfaces { public interface ISingleTonExample : : IOperation { } }
6. Lets create folder called DataAccess and add Operation implementation files in it
7. Here is the detail implementation
Operation.cs
using Dependency_Injection_Example.Interfaces; namespace Dependency_Injection_Example.DataAccess { public class Operation : ITransientExample, IScopedExample, ISingleTonExample { Guid _guid; public Operation() : this(Guid.NewGuid()) { } public Operation(Guid guid) { _guid = guid; } public Guid OperationId => _guid; } }
We implement these interfaces using a single class, Operation, that accepts a GUID in its constructor, or uses a new GUID if none is provided:
8. Lets register the interface and its implementation to Dependency Injection. Go to Program.cs and add it
// Add services to the container.
builder.Services.AddSingleton<ISingleTonExample, Operation>();
builder.Services.AddScoped<IScopedExample, Operation>();
builder.Services.AddTransient<ITransientExample, Operation>();
builder.Services.AddTransient<MyOperation2>();
9. Create Class file MyOperation2.cs under Models folder and the below code
using Dependency_Injection_Example.Interfaces; using Dependency_Injection_Example.Models; namespace Dependency_Injection_Example.Models { public class MyOperation2 { private readonly ISingleTonExample _singleton; private readonly ITransientExample _transient; private readonly IScopedExample _scoped; public MyOperation2(ISingleTonExample _singleton, ITransientExample _transient, IScopedExample _scoped) { this._singleton = _singleton; this._scoped = _scoped; this._transient = _transient; } public string GetTransientDetail() { return _transient.OperationId.ToString(); } public string GetScopedDetail() { return _scoped.OperationId.ToString(); } public string GetSingletonDetail() { return _singleton.OperationId.ToString(); } } }
9. Next, Go to HomeController
using Dependency_Injection_Example.Interfaces; using Dependency_Injection_Example.Models; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; namespace Dependency_Injection_Example.Controllers { public class HomeController : Controller { private readonly ISingleTonExample _singleton; private readonly ITransientExample _transient; private readonly IScopedExample _scoped; public HomeController(ISingleTonExample _singleton, ITransientExample _transient, IScopedExample _scoped) { this._singleton = _singleton; this._scoped = _scoped; this._transient = _transient; } public IActionResult Index() { //First Request ViewBag.Transient = _transient; ViewBag.Scoped = _scoped; ViewBag.Singleton = _singleton; //Second Request ViewBag.SecondRequest = _transient; ViewBag.Scoped2 = _scoped; ViewBag.Singleton2 = _singleton; return View(); } } }
10. Go to View
@{ ViewData["Title"] = "Home Page"; } <div class="text-center"> <h1 class="display-4">Dependency Injection Life Cycle</h1> <hr /> <h5>First Request</h5> <p>Transient : @ViewBag.Transient</p> <p>Scoped : @ViewBag.Scoped</p> <p>Singleton : @ViewBag.Singleton</p> <h5>Second Request</h5> <p>Transient : @ViewBag.Transient2</p> <p>Scoped : @ViewBag.Scoped2</p> <p>Singleton : @ViewBag.Singleton2</p> </div>
11. Lets Run the application
Dependency Injection Types:
There are four types we can achieve the Dependency Injection Types.
- Constructor Injection
- Action Injection
- View Injection
- Middleware Injection
we can inject an object to the action method Using package called Microsoft.AspNetCore.Mvc.FromServices.
public IActionResult Privacy([FromServices] MyOperation2 operationp) { ViewBag.Transient2 = operationp.GetTransientDetail(); ViewBag.Scoped2 = operationp.GetScopedDetail(); ViewBag.Singleton2 = operationp.GetSingletonDetail(); return View(); }
@inject Dependency_Injection_Example.Models.MyOperation2 operation @{ ViewData["Title"] = "Privacy Policy"; } <h1>@ViewData["Title"]</h1> <h1 class="display-4">Dependency Injection</h1> <hr /> <h5>First Request</h5> <p>Transient : @operation.GetTransientDetail()</p> <p>Scoped : @operation.GetScopedDetail()</p> <p>Singleton : @operation.GetSingletonDetail()</p>