1. Introduction
“Dependency Injection is a design pattern that takes away the responsibility of creating dependencies from a class thus resulting in a loosely coupled system.”
Or
“Dependency Injection means that this is done without the object intervention, usually by a framework component that passes constructor parameters and set properties.”
In order to understand DI you need to understand below terms:
Dependency:
Dependency means a class depends on other class’s object for its working.
Example:
public class Employee
{
private dbHelper helper;
Employee()
{
Helper = new dbHelper();
}
}
Here in this example working of class Employee is dependent on object of dbHelper.
Dependency Inversion Principle (DIP):
It states that “High-level modules should not depend on low-level modules. Both should depend on abstractions”.
Inversion of Control (IOC):
Inversion of Control (IoC) means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source (for example, an xml configuration file).
The Dependency Injection (DI) Design Pattern
At a high level, the goal of Dependency Injection is that a client class (e.g. the golfer) needs something that satisfies an interface (e.g. IClub). It doesn’t care what the concrete type is (e.g. WoodClub, IronClub, WedgeClub or PutterClub), it wants someone else to handle that (e.g. a good caddy). The Dependency Resolver in ASP.NET MVC can allow you to register your dependency logic somewhere else (e.g. a container or a bag of clubs).
The advantages of using Dependency Injection pattern and Inversion of Control are the following:
- Reduces class coupling
- Increases code reusing
- Improves code maintainability
- Improves application testing
Improves application testing
Note: Dependency Injection is sometimes compared with Abstract Factory Design Pattern, but there is a slight difference between both approaches. DI has a Framework working behind to solve dependencies by calling the factories and the registered services.
Note: Dependency Injection is sometimes compared with Abstract Factory Design Pattern, but there is a slight difference between both approaches. DI has a Framework working behind to solve dependencies by calling the factories and the registered services.
2. Why we Inject Controller Dependency?
In real life applications almost all ASP.NET MVC applications are needed to inject its dependent component. You can create component directly inside the controller instead of injecting them. In that case the controller will be strongly coupled on those components. If any component’s implementation is changed or new version of that component is released then you must change controller class itself.
Another problem you will face when you will write unit tests. You cannot run unit tests of those controllers independently (within isolation). You cannot take mocking features from unit testing framework. Without mocking, you cannot run unit test of your code in an isolated environment.
3. Controller Structure:
ASP.NET MVC framework’s controller structure is defined inside an abstract class named Controller. If you want to create any controller, first you will create a class which must be inherited from abstract class Controller. The UML class diagram of controller class and its hierarchy looks:
All controllers root interface is IController interface. Its abstract implementation is ControllerBase class. Another abstract class is inherited from ControllerBase class and name of that class is Controller. All our custom controller classes should be inherited from that Controller abstract class or its any child class.
4. Simple Controller Creation:
Create an asp.net mvc4 application and choose internet application as project template.
If you look at home controller class, then you will find that the class has no constructor
but .Net Framework will create a parameter less constructor if isn’t anyone defined.
Now I will create ILogData interface and DefaultLogData class as its implementation.
public interface ILogData
{
void Log(string logData);
}
public class DefaultLogData: ILogData
{
public void Log(string logData)
{
System.Diagnostics.Debug.WriteLine(logData, "default");
}
}
HomeController with ILogData Injection looks
public class HomeController : Controller
{
private ILogData _logData;
public HomeController(ILogData logData)
{
_logdata = logData;
}
}
Still I do not find any place where I can create DefaultLogData object in my codebase and though I am not creating HomeController object by myself so I do not find the place where I can create DefaultLogData object and how I can pass it to the HomeController with defined parameterized HomeController (IlogData logData) constructor. In that state if I build my project, it will build without any errors. But in run time it will throw exception.
5. How MVC framework creates controller:
IControllerFactory interface is responsible for creating controller object. DefaultControllerFactory is its default framework provided implementation class. If you add a parameter less constructor to the HomeController class and set break point in that and run application with debug mode, you will find that the code execution process is hold on to that breakpoint.
6. Why Custom controller factory:
Already you know that Default controller factory creates controller object using parameter less constructor. We can inject our controller by parameterless constructor too. See the code below:
public class HomeController : Controller
{
Private ILogData _logData;
public HomeController():this(new DefaultLogData())
{
}
public HomeController(ILogData logData)
{
_logData = logData;
}
}
I found many developers who are misguided the way of the above dependency injection process. This is not dependency injection at all. This actually clearly violates the dependency inversion principle. The principle says that “High level module should not depend upon the low level module, both should depend on abstraction. Details should depend upon abstraction”. In above code HomeController itself create DefaultLogme object. So it directly depends on ILogData implementation (DefaultLogData). If in future another implementation comes of ILogData interface then HomeController code itself need to change. So it is probed that it is not proper way to do. So if we need proper way to inject dependency. We need parameterized constructor, by which we can inject our ILogData component. So current implementation of DefaultControllerFactory does not support this requirement. So we need a new custom controller factory.
7. Using MEF For creating custom controller factory:
In real life project you will see experts are using IOC containers inside controller factory for creating/fetching the Controller object. Why because many problems need to raise and handle if you try to dynamically create dependent object and controller object. So it will be better approach to use any IOC container to your project and register all your dependent objects there and use it. You can use various popular IOC containers like Castle Windsor, Unity, NInject, StructureMap etc. I will demonstrate how Managed Extensibility Framework (MEF) is used in this situation. MEF is not an IOC container. It is a composition layer. You can also call it plug-able framework by which you can plugin your dependent component at run time. Almost all types of work you can do by MEF which you can do with IOC. When to use MEF when IOC it depends on your requirements, application architecture. In my suggestion is when you need to compose your component at run time( run time plug-in play) in that case you can use MEF, when you create your components with its dependent component with static reference then you can use IOC. There are many articles published online where you can find more details/technical write-up regarding that. I hope you can study more on that and easily take decision which you can use and when. By the way MEF comes with .NET framework 4.0 so main benefit is, no third party component dependency is there. First you take reference of system.ComponentModel.Composition to your project.
Then you create your custom controller factory i.e. MefControllerFactory.
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer _container;
public MefControllerFactory(CompositionContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
Lazy<object, object> export = _container.GetExports(controllerType, null, null).FirstOrDefault();
return null == export
? base.GetControllerInstance(requestContext, controllerType)
: (IController)export.Value;
}
public override void ReleaseController(IController controller)
{
((IDisposable)controller).Dispose();
}
}
CompositContainer object is works like as IOC container here. Inside GetControllerInstance method I fetch controller object from that. If found null value then I fetch it from default controller (base class) object otherwise from CompositContainer object. After creating MefControllerFactory class we need to register it to MVC framework. Registration code in Application Start event.
protected void Application_Start()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var composition = new CompositionContainer(catalog);
IControllerFactory mefControllerFactory = new MefControllerFactory(composition);
ControllerBuilder.Current.SetControllerFactory(mefControllerFactory);
}
I use InheritedExportAttribute, ExportAttribute, PartCreationPolicyAttribute of MEF to interface IloggData, HomeController.
Based on these attributes MEF framework create objects. Just one important think you should remember that when you will use MEF, you should decorate your controllers through PartCreationPolicyAttribute and set controllers life time as create object per request policy. [PartCreationPolicy (CreationPolicy.NonShared)] Without that you will get an error. By default it will use SharedCreation policy.