Raj and Mark are .Net Developers. They meet in a Coffee shop, Raj curiously asked Mark if he could explain to him the basics of Dependency Injection in simple words. They had an interesting conversation as in the following.
Raj: What is Dependency injection?
Mark: DI is a software design pattern that implements Inversion of Control. DI is also known as the inversion of a controller. To understand this you must understand tight coupling.
Raj: Please explain to me what tight coupling and DI are.
Mark: Sure. Let me use an example to explain it to you.
Consider the C# Corner web site developed with MVC, where the user submits articles and they get notification by email that the article was successfully submitted. So dummy code snippet for this.
Send the Mail
Assume we are using Google SMTP to send the mail as in the following:
- public class User
- {
- GoogleSMTPEmailSend googleSender;
- public User()
- {
- googleSender = new GoogleSMTPEmailSend();
- }
- public void PostArticle()
- {
-
- googleSender.SendEmail();
- }
- }
- class GoogleSMTPEmailSend
- {
- public void SendEmail()
- {
-
- }
- }
In the preceding code snippet, you can see tight coupling. Consider in the Future that we need to use some other SMTP like Yahoo to send the email. This needs a code change and that's why this is tightly coupled.
Raj: Okay then how to remove this tight coupling?
Mark: Here the dependency term is relevant since you can see the user is dependent on the Mail Send. This should not have a concrete class implementation. So, the control should be inversed.
Raj: How to remove this? Can we inverse the control using an interface?
Mark: Exactly. Now let's see how the code will be after implementing the interface. Will it remove the dependency completely?
- public interface IEmailSender
- {
- void SendEmail();
- }
- class GoogleSMTPEmailSend: IEmailSender
- {
- public void SendEmail()
- {
-
- }
- }
- public class User
- {
- public IEmailSender emailSender;
- public User()
- {
- emailSender = new GoogleSMTPEmailSend();
- }
- public void PostArticle()
- {
-
- emailSender.SendEmail();
- }
- }
Raj: Okay. What I can see is, it is decoupled but still you have to create a concrete object of the class here also. In other words:- emailSender = new GoogleSMTPEmailSend();
Mark: Great Raj. Yes, we have introduced more problems here as in the following:
- User: PostArticle() IEmailSender GoogleSMTPEmailSend();
PostArticle() depends on both
IEmailSender and
GoogleSMTPEmailSend
Raj: Then how can we do it without creating an object of GoogleSMTPEmailSend?
Mark: We will be creating the object but not here since it creates dependency. The solution is Dependency Injection.
Raj: Can you please explain how DI will remove the dependency completely?
Mark: Let me explain it to you. Dependency injection does this in two parts.
First part: Removes the dependency on a concrete class by ing a variable of the interface in the constructor of the User class like this.
- public class User
- {
- public IEmailSender emailSender;
- public User(IEmailSender _emailSender)
- {
- emailSender = _emailSender;
- }
- public void PostArticle()
- {
-
- emailSender.SendEmail();
- }
- }
This can be done in three ways.
- Setter property.
- Method.
- Constructor. We have seen this way of injection, in other words, Constructor Injection. You might be thinking, where is the implementation class of _emailsend or where will it be initiated?
Second Part
The answer is at runtime. At runtime, the User class will demand the implementation of the IEmailSender interface. An instance of the classes that implement the IEmailSender interface will be created and ed to the User class at runtime.
Raj: How to do that? Where to initiate the concrete class without creating a dependency?
Mark: That is a good question and the answer is DI container.
Raj: What is a DI container?
Mark: A DI Container is a component that acts as a broker between the dependencies that a class like “
User” demands and the concrete implementation of those dependencies such as
GoogleSMTPEmailSend.
So we register all the interfaces in the DI container and tell it to create an object to satisfy the dependency. So we register an
IEmailSender interface to satisfy the instance of
GoogleSMTPEmailSend that should be created whenever required.
Raj: How to create a DI Container?
Mark: There are many DI containers, like Ninject and Unit. There is no need to create a DI container since Microsoft has already created a DI Container named Unity.
I would recommend you to read an article that demonstrates Dependency Injection using Unit in MVC.
http://www.c-sharpcorner.com/UploadFile/dacca2/implement-ioc-using-unity-in-mvc-5/
Raj: Now I have answers to my questions to a great extent. Now I can see the difference in the tightly coupled in the first code snippet and IoC in the last code block.
Mark: This was a basic approach to help you understand Dependency injection.