Click here to Skip to main content
15,899,825 members
Articles / Web Development / ASP.NET

Dependency Injection Scenarios in ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.18/5 (9 votes)
16 Jun 2016CPOL8 min read 72.3K   16   19
A couple of Dependency Injection scenarios in ASP.NET MVC
In this article, you will find examples of DI in different areas of ASP.NET MVC application architecture. There will be partial code demonstration here and the entire example could be downloaded from GitHub.

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

C#
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 can we 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 injecting the required dependency into its constructor method.

C#
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.

C#
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.

C#
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.

C#
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 the 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.

C#
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:

C#
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 than 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
<?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, let's 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

C#
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

C#
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

C#
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

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

ControllerFactory

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

ValuesController

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

}

WebApiDependencyResolver

C#
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

C#
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.

History

  • 16th June, 2016: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
Just a regular guy interesting in programming, gaming and a lot of other stuff Smile | :)

Please take a moment to visit my YouTube Channel and subscribe to it if you like its contents!
My YouTube Channel

Don't be a stranger! Say Hi!!

Cheers!

Comments and Discussions

 
QuestionWhat's about IoC Containers? Pin
Michael Freidgeim21-Dec-16 10:03
Michael Freidgeim21-Dec-16 10:03 
QuestionDI has its place but needs to stay there... Pin
Member 43662206-Jul-16 23:16
Member 43662206-Jul-16 23:16 
QuestionControllers that doesn't need DI Pin
Luis M. Teijón25-Jun-16 7:08
Luis M. Teijón25-Jun-16 7:08 
AnswerRe: Controllers that doesn't need DI Pin
Nitij27-Jun-16 20:13
professionalNitij27-Jun-16 20:13 
GeneralRe: Controllers that doesn't need DI Pin
Luis M. Teijón6-Jul-16 17:57
Luis M. Teijón6-Jul-16 17:57 
QuestionThe Overuse of Dependency Injection Pin
Chris Solutions17-Jun-16 11:15
professionalChris Solutions17-Jun-16 11:15 
AnswerRe: The Overuse of Dependency Injection Pin
Nitij17-Jun-16 21:30
professionalNitij17-Jun-16 21:30 
GeneralRe: The Overuse of Dependency Injection Pin
Chris Solutions18-Jun-16 17:38
professionalChris Solutions18-Jun-16 17:38 
GeneralRe: The Overuse of Dependency Injection Pin
Nitij19-Jun-16 21:28
professionalNitij19-Jun-16 21:28 
GeneralRe: The Overuse of Dependency Injection Pin
John Brett22-Jun-16 1:49
John Brett22-Jun-16 1:49 
AnswerRe: The Overuse of Dependency Injection Pin
John Brett20-Jun-16 0:12
John Brett20-Jun-16 0:12 
GeneralRe: The Overuse of Dependency Injection Pin
Chris Solutions21-Jun-16 19:11
professionalChris Solutions21-Jun-16 19:11 
The whole point of using DI is to separate out components into modules that focus upon a single responsibility, and this leads to more reusable code

That is not true. What you've described is loose-coupling, not DI. It is the use of interfaces that enables loose-coupling. You can also achieve loose-coupling via events. DI is the "injection" of dependencies into an object. That "dependency" can be just about anything.

The problem with DI is that it mandates that an object's internal be exposed and shifts the burden of such management outside of the object that once performed internal management unbeknownst to the client. The internal's lifetime that would normally go out of scope as the object goes out of scope become ambiguous with DI.

if you are writing code that is not readily testable, you should reconsider your design

I respectfully disagree. You should write code that provides features as outlined in the requirements and nothing more (the definition of YAGNI). Your testing should reflect the use of what you are developing (mainline, boundary, exception, etc). You shouldn't have to "expose" your component's internal to be "testable" or be forced to use interfaces solely to mock your objects. In other words you are altering your design and architecture for the sole purpose of testing; having nothing to do with the requirements.

If QA find a bug then the developer who wrote the component should fix it. This mean what is really important is not "testability" but maintainability. Developers should be able to debug the object, API, component, etc. easily to resolve bugs. DI has the tendency to complicate the code especially via reflection and hidden object creation that frustrates debugging and thus lowers maintainability.

Don't conflate SOLID and TDD - the two are both very powerful tools

There is no confusion. My point is that SOLID & TDD encourages the prolific use of DI. My point is that DI should be limited to only when an object has a dependency on an interchangeable source. For example, an object that uses interchangeable sources to persist its data.

The paranoia over encapsulation taken to its extreme results in inflexible and unchangeable code

"Paranoia" occurs with DI as well especially due to SOLID & TDD. My point is that its use adds undue complexity and burdens where they are simply not needed and uncalled for. Encapsulation is not the problem. The problem is tight-coupling, not right-sizing responsibilities, and failing to refactor dependencies. Getting that right requires a good deal of governance.

I'm disappointed that Microsoft decided to include DI into their latest release of MVC. This decision must be left to the governance of developers and should not be part of any framework.

Cheers.
GeneralRe: The Overuse of Dependency Injection Pin
John Brett22-Jun-16 2:01
John Brett22-Jun-16 2:01 
GeneralRe: The Overuse of Dependency Injection Pin
Chris Solutions22-Jun-16 13:53
professionalChris Solutions22-Jun-16 13:53 
GeneralRe: The Overuse of Dependency Injection Pin
John Brett23-Jun-16 4:50
John Brett23-Jun-16 4:50 
GeneralRe: The Overuse of Dependency Injection Pin
John Brett23-Jun-16 5:04
John Brett23-Jun-16 5:04 
GeneralRe: The Overuse of Dependency Injection Pin
John Brett22-Jun-16 2:03
John Brett22-Jun-16 2:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.