DotNetCurry Logo

Dependency Injection (DI) in ASP.NET MVC 6

Posted by: Mahesh Sabnis , on 2/6/2016, in Category ASP.NET MVC
Views: 21985
Abstract: ASP.NET MVC 6 has inbuilt support for Dependency Injection, which can be used for implementing decoupling across different layers of our ASP.NET MVC application.

In the field of Software Development, Design Patterns are discussed with great interest. This is a topic which grabs the attention and intension of every software developer as they want to learn and use it. Technically, Design Pattern is a general solution to a commonly occurring problem. These pattern varies from Object Creation (Creational) to Structural as well as Behavioral.

Editorial Note: Check out some .NET Design Patterns in our article .NET Design Patterns – A Fresh Look

Applications are divided across multiple layers or components. These components could be created by different teams located at different geographical locations, or even by third party vendors. In such cases, establishing communication across these components in a decoupled manner is a big challenge. A major problem may occur when the third-party component is modified with logic or with operation implementation, in which case, the component depending on it may crash.

 

This situation is often challenging for developers and often requires the need of a simple pattern using which dependency across components can be handled easily.

What is Dependency Injection (DI)?

Technically, Dependency Injection or DI is defined as a software design pattern which implements Inversion of control (IOC) for resolving dependencies across objects. The dependency is an object (or a service object), which is passed as dependency to the consumer object (or a client application). This is a pattern using which decoupling (or loose-coupling) across components can be implemented easily.

When ObjectA wants to access methods (or operations) of ObjectB, then instead of directly instantiating ObjectB in ObjectA, ObjectB is injected into ObjectA as a dependency. In this case, ObjectB implements an interface, which is passed to ObjectA. Hence ObjectB is not instantiated using new in ObjectA. The advantage of this approach is that if in future ObjectB has any modifications, ObjectA need not be refreshed.

The following image (not a class diagram) provides an overview of the above scenario.

dependency-injection-mvc

In systems based on DI implementation, those classes that want to request for dependencies are passed the dependencies using constructors, properties and methods. In such cases, we must have a class who takes responsibility of providing instances of types (dependencies) to those classes who want them (a client). The class which takes this responsibility is called as Dependency Injection Container. The Container is also known as a factory responsible for providing instances of dependencies to the client. More information on DI can be read from this link.

Dependency Injection in ASP.NET Core 1.0

ASP.NET 5 is now known as ASP.NET Core 1.0. In the ASP.NET Core 1.0 release, Web API is merged with ASP.NET MVC, termed as MVC 6. ASP.NET MVC 6 is designed from scratch with an inbuilt support for Dependency Injection. It can take an advantage of built-in framework services which are responsible for registering the dependencies in the Startup class. As we have seen in Section 1, we need a container for managing dependency objects. In ASP.NET Core 1.0, we have IServiceProvider interface which supports DI using constructor injection mechanism. This is the default DI mechanism supported by ASP.NET Core 1.0 for providing service dependencies to application.

Practical Implementation of Dependency Injection

We will implement an application using the Free Visual Studio 2015 Community Edition and ASP.NET Core 1.0. Download Visual Studio 2015 Community Edition and ASP.NET Core 1.0 (previously known as ASP.NET 5).

Step 1: Open Visual Studio 2015 and create a new ASP.NET Web Application as shown in the following image:

aspnet-app

Click on OK, this will display a New ASP.NET Project window as shown in the following image. Select Empty template in the ASP.NET 5 Templates as shown in the following image:

aspnet5-web-app

Click on OK to generate the application.

Step 2: Open Startup.cs file from the project. This contains a Startup class with ConfigureService() method as shown in the following code:

public void ConfigureServices(IServiceCollection services)
{

}

The above method is responsible for defining services which will be used by an application. This method is called by runtime. This method can be used to add services in the container so that their instances can be available to all the client objects e.g. Controllers. The IServiceCollection is used to contain all services.

Note: If we use the readymade template, instead of the Empty application template we chose above, by default Visual Studio generates readymade code which adds additional services e.g. AddMvc(), AddEntityFramework(), AddIdentity(). For our example, we have chosen Empty template to understand the process better.

Step 3: In the project, add the Models folder and in this folder add a class file of the name ModelClasses.cs. In this class file, add following code

using System.Collections.Generic;

namespace ASPNET5_DIApp.Models
{
    public class EmployeeInfo
    {
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
    }

    public class EmployeeDatabase : List     {         public EmployeeDatabase()         {             Add(new EmployeeInfo() { EmpNo = 1, EmpName = "A" });             Add(new EmployeeInfo() { EmpNo = 2, EmpName = "B" });             Add(new EmployeeInfo() { EmpNo = 3, EmpName = "C" });             Add(new EmployeeInfo() { EmpNo = 4, EmpName = "D" });             Add(new EmployeeInfo() { EmpNo = 5, EmpName = "E" });         }     }      public class DataAccess     {         public List Get()         {             return new EmployeeDatabase();         }     } }

The above code has EmployeeInfo class as the Entity class, and the EmployeeDatabase is derived from List which initializes the Employee Data. The DataAccess class contains Get() method which returns all Employees.

Step 4: In the project, add a new folder of name Services. In this folder, add a class file of name Service.Svc with following code:

using ASPNET5_DIApp.Models;
using System.Collections.Generic;

namespace ASPNET5_DIApp.Services
{
    public interface IService where TEntity : class     {         IEnumerable Get();     }     public class EmployeeInfoService : IService     {         DataAccess ds;         public EmployeeInfoService()         {             ds = new DataAccess();          }         public IEnumerable Get()         {             return ds.Get();         }     } }

The above code contains generic IService interface. TEntity has set constraints for the class. The interface contains Get() method which returns IEnumerable.

Step 5: In the project.json, add the following dependencies:

"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final",
"Microsoft.Extensions.CodeGenerators.Mvc": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",

The above dependencies are used for MVC application. Please go through this link to read the use of these dependencies.

Step 6: We need to register our service created in Step 4 in the ConfigureServices() method. In ASP.NET Core 1.0, we have the following Service Lifetime and Registration Options.

  • Transient
    • In this case the transient lifetime services are created each time when they are requested.
    • This object is always different. Every time a new instance is provided to each controller and service.
    • This lifetime is best for the stateless and lightweight services.
  • Singleton
    • The Singleton lifetime services are created when they are requested for the first time. For the next new request, the same instance is used.
    • This approach is more useful in case the application needs singleton behavior. We can take advantages of Singleton lifetime service instead of creating our own class using the singleton design pattern.
  • Scoped
    • The scoped lifetime services are created once per request in current scope. This is equivalent to Singleton for the current scope.
    • These objects are same within requests, and different across different requests.
  • Instance
    • A specific instance is given all the time. This instance will be used for all subsequent requests. This is similar to the Singleton instance. The only difference is that the singleton service is lazy-loaded when it is requested for the first time, whereas instance is created in the ConfigurationServices method.
    • These objects are the same for every request.

 

Step 7: Add the following code in Startup.cs.

The ConfigureServices() method

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddSingleton

The above method adds the MVC service in the Service collection followed by the registration of the Singleton Service lifetime for EmployeeInfoService.

The Configure() method

public void Configure(IApplicationBuilder app)
{
    app.UseIISPlatformHandler();
    app.UseDeveloperExceptionPage();
    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=EmployeeInfo}/{action=Index}/{id?}");
    });
}

The above method uses the MVC service and defines routing.

Step 8: In the project, add a new folder of name Controllers. In this folder, add a new MVC Controller class (Right-Click > Add > New Item > MVC Controller class). Rename this class as EmployeeInfoController. In this controller, add the following code:

public class EmployeeInfoController : Controller
{

    public IService _service { get; set; }     public EmployeeInfoController(IService srv)     {         _service = srv;     }      // GET: //     public IActionResult Index()     {         var Emps = _service.Get();         return View(Emps);     } }

The above code shows Constructor Injection for the IService object for the EmployeeInfoController class. Put a breakpoint on the Constructor (on any other line inside). When the application runs for the EmployeeInfoController, the following result will be displayed

debug-mvc

This shows an instance of EmployeeInfoService is injected in the Constructor.

Using Different DI Containers than the default provided by ASP.NET Core 1.0.

As one may require, we can make use of other DI Containers to register our dependencies in container and inject it to the objects depending on them. But in case of ASP.Net Core, we need to use DI containers which are compatible with DNX. Please visit this link to know more about the DNX supported DI Containers. In our application we will be using Autofac. This is an addictive IOC container for .NET 4.5 apps with support for DNX. More information about this can be found from this link.

Step 1: To use Autofac, add the following dependencies in project.json file:

"Autofac": "4.0.0-rc1",
"Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177"

Step 2: In the project, add a new folder of name AutoFacDependencyContainer. In this folder, add the following class:

using ASPNET5_DIApp.Models;
using ASPNET5_DIApp.Services;
using Autofac;

namespace ASPNET5_DIApp.AutoFacDependencyContainer
{
    public class DependencyRegistrationModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType().As

The above class is the Module class used to register the EmployeeInfoService in the ContainerBuilder object. This class is derived from the Module class. The Module class is used to define user defined modules which are used to add a set of related components in the container. In our case, it is EmployeeInfoService class and IService interface. This DepdencyRegistrationModule class is used to build the container from the registrations passed to it.

Step 3: Since we are using third-party container, we need to change the ConfigureServices() method. This will return IServiceProvider. This interface defines a mechanism for retrieving service object which can be added as dependencies to other objects.

In Startup.cs, add the following namespaces.

using Autofac;
using ASPNET5_DIApp.AutoFacDependencyContainer;
using Autofac.Extensions.DependencyInjection;

Modify the ConfigureServices() method as following:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    var objectBuilder = new ContainerBuilder();
    objectBuilder.RegisterModule();     objectBuilder.Populate(services);      var objectContainer = objectBuilder.Build();     return objectContainer.Resolve(); }

The above code creates an instance of the ContainerBuilder class. Using RegisterModule() method, call the DepdencyRegistrationModule class to register in the ContainerBuilder. The IOC container is created using Build() method with the component registrations in it. Finally the ConfigureServices() returns the IServiceProvider with retrieved services using Resolve() method.

To run this application, as mentioned in Step 8, apply breakpoint on the EmployeeInfoController constructor, and we will find the EmployeeInfoService instance is passed as dependency to the constructor.

Conclusion

Dependency Injection is used for objects that have complex dependencies e.g. Repositories, Services, and Adapters. Such objects are recommended to be registered in a container and injected as dependencies to other objects. ASP.NET Core 1.0 has provided inbuilt support for Dependency Injection, we can use it for implementing decoupling across different layers of our application.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!