Dependency Injection Container






4.60/5 (5 votes)
Dependency Injection (DI) Container
Introduction
DI is a framework to create dependencies and inject them automatically when required. Dependency Container automatically creates objects and injects them when required.
Background
Dependency Container makes the task easy while you can manage the dependency without DI Container, but it is tough to maintain them without DI Container.
Use of Dependency Injection Container
Problem: Suppose you need to create an object in this way, which seems too complicated:
var svc = new Product(new Location(),new Price(), new VAT(),
new ServiceTax(new LogWriter()),new Logger(new EmailSender(new LogWriter ())));
To solve this complexity issue, Dependency Injection Container comes in light.
By using IoC, you can write like that:
var svc = IoC.Resolve<IShippingService>();
What Was the Problem Before IoC Container?
Suppose you are creating a singleton object, you can do this like:
Class XmlValidation
{
Private XmlValidation xmlValidator=null;
Public XmlValidation GetXmlValidatior()
{
if(xmlValidator ==null)
xmlValidator = new XmlValidation();
return xmlValidation;
}
}
But this is not thread safe because in if
block, two threads can simultaneously enter. To make it thread safe, you use some locking mechanism.
But you have to write this code, you need to build some logic, test it well and maintain it. In the same way, you may need some other type of objects like only one object per thread, one object per ASP.NET web request. For all of this, you need to write code and maintain it.
Here, Container comes into the picture. You can give control of creating object to container and tell it which type of object you have required.
Window Form Library is one of the best examples of Container. It controls the instantiation and lifespan of your objects.
Inversion of Control means that you are inverting the control (control of object creation) to someone else (container) from your side.
There are various predefined containers like Windsor, Ninject, Sprint.Net, etc. Let us see an example how to use Windsor.
public class IoCSample
{
private IWindsorContainer container;
public void InitializeContainer()
{
container = new WindsorContainer();
container.Register(
Component.For<smtpclient>());
}
}
One major benefit of using container is lifestyle management. Suppose you want to create singleton object of XmlValidation
class. Windsor by default lifestyle is Singleton.
public void IsSingleton()
{
var client1 = container.Resolve<xmlvalidation>();
var client2 = container.Resolve<xmlvalidation>();
if( client1 == client2)
{
return true;
}
return false;
}
It will return true
.
So you use the above method for thread safe singleton pattern. And it is well tested by thousands of users.
If you want a new object every time, then you need to modify:
container.Register(
Component.For<xmlvalidation>()
.LifeStyle.Is(LifestyleType.Transient)
);
When you call IsSingleton()
method, it will return false
; Windsor supports 5 types of lifetstyle.
Singleton (default)
Pooled
Per Web Request
Transient
Thread
If you need some customized lifestyle, you can create your own and plug it into Windsor.
How To Use It With Interface?
public interface ITest
{
void Go();
}
public class Test: ITest
{
public void Go()
{
}
}
Then object can be registered as:
container.Register(Component.For().ImplementedBy());
You can access the object of container like that:
ITest test = container.Resolve();
If there are multiple classes (Test
and Test2
), implement ITest
interface and you need to use both classes in the same code, then you can:
container.Register(
Component.For<itest>().ImplementedBy<test>().Named("Test1"));
container.Register(
Component.For<itest>().ImplementedBy<test2>().Named("Test2"));
And access the object like that:
ITest test1 = container.Resolve<itest>("Test1");
ITest test2 = container.Resolve<itest>("Test2");
But still you have to use container.Resolve()
method at every place where required. Here, dependency Injection helps to solve this problem.
Dependency Injection
Suppose there is a website which required payment for registration:
public interface IPayment {
bool Payment(string cardNumber, decimal amount);
}
public interface IValidation {
bool ValidationUser(UserInformation userInformation);
}
public class RegistrationPrcocess
{
public RegistrationPrcocess(
IPayment processor,
IValidation validation)
{
}
}
You can implement like that:
var payment = container.Resolve<ipayment>();
var validation = container.Resolve<ivalidation>();
var service = new RegistrationPrcocess(payment, validation);
You also can register a different IPayment
in the container without making changes in code. Suppose you have required new IPayment
, then you need to change the container initialization to use the new implementation.
Here, you don’t need to call container.Resolve()
at every place. The IPayment
and IValidation
are already registered in the container. So you need to define ResitrationProcess
in constructor only. The container will inject those dependencies for us.
You can register RegistrationPrcocess
in container itself as below:
container.Register(
Component.For<registrationprcocess>()
.LifeStyle.Is(LifestyleType.Transient));
When required, access the object of RegistrationPrcocess
using Resolve
. You can simply call Resolve
method. The container checks the constructor and finds that IPayment
and IValidation
are required, then you don’t need to pass the object of IPayment
and IValidation
object. The container checks if IPayment
and IValidation
are registered, if they are already registered, then container will resolve those types automatically and one can easily instantiate Registration Service. You are required to Resolve RegistrationRrocessOnly
. Nothing more than that.
var service = container.Resolve<registrationprcocess>();
What is the real benefit of container
? Suppose in future you are required to send mail to every registered user, then, you write an Interface
like IEMailSender
. Then, you need to change in constructor only like:
public interface IEmailSender
{
void SendMail(MailMessage message);
}
public class RegistrationPrcocess
{
public RegistrationPrcocess(
IPayment processor,
IValidation validation,
IEmailSender emailSender)
{
}
}
So, nowhere else other than constructor required to change for EMailSender
. In case of simple code, you need to change everywhere wherever object is created.
1. Easy in doing unit testing, Each object can be tested separately
2. Easy and flexible configuration
3. It can provide simplified design, with faster and less error prone development
4. It is easy to substitute one object from another using pluggable architecture
Points of Interest
In this article, we have discussed about Dependency Injection Container and Inversion of Control Container.
History
- 11th April, 2016: First version