Dependency Injection Scenarios in ASP.NET MVC
A couple of Dependency Injection scenarios in ASP.NET MVC
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 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.
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 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.
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 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 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
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.
History
- 16th June, 2016: Initial version