Monday, February 2, 2015

Dependency Injection in MVC

Why do we need DI?
Dependency injection is very hot topic in current web world. Having DI in MVC has its own advantage. Let’s take a scenario –
I have a controller named as HomeController and it is calling a service to fetch some data.
Simple answer is we create the instance of service in the Controller itself and use it. But it won’t let us write testable code, because somebody creating Controller object in his/her test case will have to create service object first. What if we have some dependency in service also.  Tester will have to spend lot of time resolving these dependency, rather than focusing on the controller test cases.
So we should never rely upon the instance of the service in the controller, instead we should have interface. Using this we can easily mock it for our testing. Also in future if we want to replace it with some other service instance, it will be pretty straight forward to replace.

DI in MVC –
Now we agree on having a reference of interface type in the controller(because of obvious reason), now the question comes is, where to initialize it? Ideally it should be passed as a parameter to the controller, because it is not controller’s responsibility to create the service(testable code). But default MVC won’t allow us to have parameterized constructor of controller.
In order to achieve this objective we have been provided with ControllerFactory and Dependency resolver. Let’s learn in detail how it works.

Controller Creation –
MVC handler request controllerbuilder to give object of type IControllerFactory.
Controller builder- It is responsible for getting the controllerfactory.
ControllerFactory – Responsible for resolving the correct controller object
In the lifecycle of MVC, once we hit the URL, routing redirects our request to MVCHandler and which in terns request controllerBuilder for IControllerFactory object. This object is responsible for providing the object of controller. MVC provide default implementation of ControllerFacotry with name DefaultControllerFactory. This factory calls the default constructor of controller and give us the object of it.


In MVC, Every controller inherits Controller(abstract) class, which in tern inherits from ControllerBase(abstract) which inherits from IController.

Customization of Controller – 
We can create our own ControllerFactory and replace the default factory with it. We can write our own logic of how to resolve the controller. Her is the example of Controller MyController and we are introducing dependency of a service in it-
ControllerFactory implements IControllerFactory interface. 

The interface has mainly 3 methods in it – 
IController CreateController(RequestContext requestContext, string controllerName);       
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);      
void ReleaseController(IController controller);
We can create our own custom factory in the following manner – 
public class MyControllerFactory : IControllerFactory
    {
        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
//Special logic to handle our controller
            if (controllerName.Equals("My"))
            {
                var svc = new MySVC();
                return new MyController(svc);
            }
            else
            {
// Default handling for other controllers
                return new DefaultControllerFactory().CreateController(requestContext,controllerName);
            }
        }
        public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }
        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
                disposable.Dispose();
        }
    }

We need to register this factory in Global.asax -> application start event – 
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());

Setting current factory using ControllerBuilder will modify the current factory and will invoke our code on resolving the controller.