Dependency Injection Scenarios in ASP.NET MVC 5

Datetime:2016-08-23 04:38:27          Topic: ASP.NET MVC           Share

Introduction

Dependency injection is a programming and application design pattern which is being used by developers for so many years now. This pattern comes as a default programming syntax in many frameworks like Angular and we must follow them in order to use the framework. I will not go much into explaining what Dependency Injection actually is because there is much information available on the subject which could be accessed using a simple web search. Here is the formal definition from Wikipedia:

Quote:

In software engineering, dependency injection is a software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it.

Dependency Injection promotes loose coupling between application modules and provides us means to switch code modules being used without building and redeploying the entire application or parts of it. This could be done by using either application configuration file or by reading dependency information from a database table.

We can create a DI code framework of our own for custom scenarios. But in Asp.Net Mvc in order to use DI in certain areas we must follow the .Net approach. This could be done by implementing in-built interfaces into classes and wiring them up from Global.asax when the application starts.

I am assuming that you are aware of dependency injection as a design pattern and as a programming concept before you start reading further. In this article I will be giving examples of DI in different areas of Asp.Net Mvc application architecture. There will be partial code demonstration in this article and the entire example could be downloaded from either here or from GitHub where I have uploaded it in a public repository.

Using the code

Create an empty Asp.Net Mvc application. Add a single HomeController, Index view and a Web Api Controller.

Controller Class Dependency Injection

Controller classes are extensively used in the Asp.Net Mvc from simply returning the html view to the browser to providing Get and Post methods which could be invoked from the client side. So many times we need to do things like data access, error logging, caching etc. from a controller class. Now there are a couple of ways to do this. The standard way is to just create an object out of the manager class which contains the data access logic and use it directly. But there are several issues in this approach.

The manager class will be tightly bound to the controller class and in order to use a different manager class implementation we would have to make changes to the controller code and re-deploy the application after building it. There could be several such classes that the controller class could need to perform the essential business logic operations which means more changes.

DataManager Class

namespace DIScenarios.Managers
{
    public class DataManager
    {
        public Object GetData()
        {
            throw new NotImplementedException();
        }
    }
}

This could be handled by dynamically providing the controller class its dependencies whenever an object is created out of it. For this purpose we can inject the required dependency into the constructor of the controller class. Now the question arises that from where we can actually inject the dependency. To do this we will need to implement the System.Web.Mvc.DefaultControllerFactory class which inherits its class contract from IControllerFactory interface.

The DefaultControllerFactory will be extended into the ControllerFactory class. In the ControllerFactory we need to implement the GetControllerInstance() method. Based on the type of controller being requested we can return appropriate controller object by inject the required dependency into its constructor method.

namespace DIScenarios.Controllers
{
    public class HomeController : Controller
    {
        private DataManager _manager;
        public HomeController(DataManager manager) 
        {
            _manager = manager;
        }

        /// <summary>
        /// Returns the Index view.
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            //using the injected manager dependency to return the object model to the view.
            return View(_manager.GetData());
        }
    }
}

The question arises that how will the ControllerFactory get the reference of the dependency which it will later insert into the controller. For this we will again use constructor injection pattern; create a ControllerFactory constructor and have an argument of the manager class. The constructor will set the given argument into a private manager member.

namespace DIScenarios
{
    public class ControllerFactory : DefaultControllerFactory
    {
        private DataManager _manager;
        public ControllerFactory(DataManager manager)
        {
            _manager = manager;
        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            return controllerType == typeof(HomeController) ? new HomeController(_manager) : null;
        }
    }
}

The ControllerFactory can finally be used in the Global.asax file. We will have to use the ControllerBuilder class to dynamically create the controllers and inject the required dependency into them. After everything is done we can finally run the application and can see the dependency object injected into the controller class. You can see everything in action in the attached code.

namespace DIScenarios
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            DataManager dataManager = new DataManager();

            #region Controller Dependency Injection

            ControllerBuilder.Current.SetControllerFactory(new ControllerFactory(dataManager));

            #endregion Controller Dependency Injection            
        }
    }
}

The ControllerFactory basically acts in the middle of the controller object's request and response. It allows us to do loads of other stuff before we can actually create the controller class object and return it to be used by the Asp.Net Mvc.

This was all about injecting dependencies into the controller class. There is another area in which we need to follow the .Net practices to inject objects and that is the Web Api controller class. Web Api dependency injection works almost the same as the controller injection which you will see in the next section.

Web Api Controller Class Injection

To pass dependencies into the Web Api controller we will have to follow the same design pattern and that is to pass the dependency reference into the constructor function. The constructor will then set the reference into a private member and this will allow us to use it from anywhere inside the api controller class object.

namespace DIScenarios.ApiControllers
{
    public class ValuesController : ApiController
    {
        private DataManager _manager;
        public ValuesController(DataManager manager)
        {
            _manager = manager;
        }

        // GET api/<controller>
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/<controller>/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/<controller>
        public void Post([FromBody]string value)
        {
        }

        // PUT api/<controller>/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/<controller>/5
        public void Delete(int id)
        {
        }
    }
}

We used IControllerFactory interface implementation to pass along the dependency to the controller class when the application starts. For Web Api we will need to implement the IDependencyResolver interface and specifically the GetService() method. We will again have to do type checking like we did in previous section and will create the appropriate api controller class object along with passing the dependency object.

The IDependencyResolver interface contract will be implemented into a WebApiDependencyResolver class and it will have a constructor function to get the dependencies which it will then pass along into various api controller classes.

namespace DIScenarios
{
    public class WebApiDependencyResolver : IDependencyResolver
    {
        private DataManager _manager;

        public WebApiDependencyResolver(DataManager manager)
        {
            _manager = manager;
        }

        public Object GetService(Type serviceType)
        {
            return serviceType == typeof(ValuesController) ? new ValuesController(_manager) : null;
        }

        public IEnumerable<Object> GetServices(Type serviceType)
        {
            return new List<Object>();
        }

        public IDependencyScope BeginScope()
        {
            return this;
        }

        public void Dispose()
        {

        }
    }
}

In the above the code is first checking the type of api controller object requested and it is injecting the manager object dependency into the constructor.

Like the ControllerFactory the WebApiDependencyResolver also works in the middle of api controller request and response pipeline. We have to implement the WebApiDependencyResolver class in the Global.asax file like we did in the case of the ControllerFactory class. For this purpose we will have to use the GlobalConfiguration object; we can set the DependencyResolver property of GlobalConfiguration with our own custom api dependency resolver. This has been done in the following code:

namespace DIScenarios
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            
            DataManager dataManager = new DataManager();
            #region Web Api Dependency Injection

            GlobalConfiguration.Configuration.DependencyResolver = new WebApiDependencyResolver(dataManager);

            #endregion Web Api Dependency Injection
        }
    }
}

When the application is run then whenever the api controller is called from the client the Asp.Net Mvc will use our custom dependency resolver to create the api controller object and would then be able to inject the required dependency into the object made out of the api controller class.

Controlling Injection Using Configuration Settings

We have seen in the above sections how we can inject dependencies into the Mvc controller and api controller in the simplest manner. But the above implementation is still not dynamic. Suppose we need to update the type of manager class implementation being used, then we would need to modify the code in several places to use the new manager class implementation. This is a big setback because every time we change the code we would need to rebuild and deploy the entire application or at least some parts of it.

This problem could be resolved by reading the dependency information from the application configuration. Now this configuration could be either in an external config file or it could be in the database. In any case if we decide to change the dependency information then the entire application will need to be restarted but it is less disruptive then redeploying the entire thing again. At least we would not have to do the integration testing between the dependency and the controller class.

Let us now see how to do this implementation. We will need to read the dependency information and then based on that the code will create an object dynamically and will insert it into to the constructor. In the configuration we will store the name of the injectable manager class in text form along with its entire namespace information.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    ...
    <add key="DataManagerClass" value="DIScenarios.Managers.DataManagerMySQL" />
  </appSettings>

  <system.web>    
    ...
  </system.web>

  <system.webServer>
    ...
  </system.webServer>
</configuration>

Now in the controller, ControllerFactory and Global.asax we will need to use an interface which will enforce common implementation in all the different manager classes. We will be injecting the dependency in the form of the interface so that we won't need to worry about the specific type of manager class.

For this lets add a new interface which we will use to inject the dependency and it will also act as the class contract for the manager class.

IDataManager

namespace DIScenarios.Interfaces
{
    public interface IDataManager
    {
        Object GetData();
    }
}

Let's also create another manager class implementation which we can switch to as per our needs in the config file.

DataManagerMySQL

namespace DIScenarios.Managers
{
    public class DataManagerMySQL : IDataManager
    {
        public Object GetData()
        {
            throw new NotImplementedException();
        }
    }
}

Following changes are needed to be made in all the classes:

DataManager

namespace DIScenarios.Managers
{
    public class DataManager : IDataManager
    {
        public Object GetData()
        {
            throw new NotImplementedException();
        }
    }
}

The normal DataManager will now simply inherit from the IDataManager interface.

HomeController

public class HomeController : Controller
{
    private IDataManager _manager;
    public HomeController(IDataManager manager)
    {
        _manager = manager;
    }
}

ControllerFactory

public class ControllerFactory : DefaultControllerFactory
{
    private IDataManager _manager;
    public ControllerFactory(IDataManager manager)
    {
        _manager = manager;
    }
}

ValuesController

namespace DIScenarios.ApiControllers
{
public class ValuesController : ApiController
{
    private IDataManager _manager;
    public ValuesController(IDataManager manager)
    {
        _manager = manager;
    }

}

WebApiDependencyResolver

public class WebApiDependencyResolver : IDependencyResolver
{
    private IDataManager _manager;

    public WebApiDependencyResolver(IDataManager manager)
    {
        _manager = manager;
    }
}

As you can see in the above code we are now using IDataManager interface instead of the DataManager class. We can anytime switch between normal DataManager and DataManagerMySql in the config file.

In the global.asax file the dependency object will be created in the following way after reading its class name from the config file:

Global.asax.cs

namespace DIScenarios
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            #region Figure out the type of dependency to use from the application configuration file

            String type = WebConfigurationManager.AppSettings["DataManagerClass"];
            IDataManager dataManager = Activator.CreateInstance(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, type).Unwrap() as IDataManager;

            #endregion Figure out the type of dependency to use from the application configuration file

            #region Controller Dependency Injection

            ControllerBuilder.Current.SetControllerFactory(new ControllerFactory(dataManager));

            #endregion Controller Dependency Injection

            #region Web Api Dependency Injection

            GlobalConfiguration.Configuration.DependencyResolver = new WebApiDependencyResolver(dataManager);

            #endregion Web Api Dependency Injection
        }
    }
}

In the above code Activator.CreateInstance() is being used to create the manager class object using the class name. The type of object created will have no impact on the functionality as we are now using interface instead of a class inside the controllers.

This was all about dependency injection in this article. The code is as simple as it can get but for production environment you might want to do much more like adding validations, more complex type checking etc.

Feel free to ask any questions or provide any constructive suggestions.





About List