Dependency Injection in ASP.Net Core Application

Dependency Injection is a design pattern in which dependencies are injected into a class at runtime. This software pattern ensures the system is loosely coupled and have high code reusability. So typically we have an interface which defines the signature of the whole contract, and then we have different implementations (not necessarily many, but at least one) of the same interface. Now we have Web Application which is dependent on this interface. Then using Dependency injection we can inject the right implementation (there should be mapping of interface and implementation either in configuration file or at Startup.cs) of the interface at runtime (or whenever the web application is in need of).

In previous ASP.Net versions, there is no built in support for DI. We used to get DI functionality through 3rd party frameworks like Ninject, StructureMap etc. But starting from ASP.Net Core, we have built in support for DI. In this tutorial we are going to see how DI can be achieved in ASP.Net Core Web API Application.

NOTE: Updated this tutorial on 2/26/2017 with MSBuild based Dotnet SDK.

Create an ASP.Net Core Application using VS 2017. I am using following version of SDK which is based on MSBuild/CSProj (remember that previous versions of ASP.Net Core are based on Project.json/XProj.).

 image

Lets start from where we are at with our previous tutorial – CRUD Operations with ASP.Net Core Web API. In the previous tutorial, we have added Student controller and placed all the API code in it. Now to make the actual use of Dependency Injection, we will move the business logic to a .Net Core Class Library project.

Add a new .Net Core Class Library Project and select add new project with name AspNetCoreClassLibrary. Create three new classes -

  1. IStudentOperations.cs
  2. StudentOperations.cs
  3. Student.cs

Lets remove Student class from Web applications (delete both Student.cs file and Model folder as well) and place it in Student.cs file.

namespace AspNetCoreClassLibrary
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

Place below code in IStudentOperations.cs.

using System.Collections.Generic;

namespace AspNetCoreClassLibrary
{
    public interface IStudentOperations
    {
        Student Add(Student student);
        IEnumerable<Student> GetAll();
        Student GetById(int id);
        void Remove(int id);
        Student Update(int id, Student student);
    }
}

The actual implementation of IStudentOperations is going to be in StudentOperations.cs.

using System;
using System.Collections.Generic;
using System.Linq;

namespace AspNetCoreClassLibrary
{
    public class StudentOperations : IStudentOperations
    {
        private static List<Student> _students = new List<Student>();
        public Student Add(Student student)
        {
            _students.Add(student);
            return student;
        }

        public IEnumerable<Student> GetAll()
        {
            return _students;
        }

        public Student GetById(int id)
        {
            return _students.FirstOrDefault(p => p.Id == id);
        }

        public void Remove(int id)
        {
            var _student = _students.FirstOrDefault(p => p.Id == id);
            _students.Remove(_student);
        }

        public Student Update(int id, Student student)
        {
            _students.FirstOrDefault(p => p.Id == id).Name = student.Name;
            return student;
        }
    }
}

Now lets add reference of our class library to Web application project. You can simply add below line in CSProj of Web Application project.

<ItemGroup>
  <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore" Version="1.0.3" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.2" />
  <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.1" />
</ItemGroup>
<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup>
<ItemGroup>
  <ProjectReference Include="..\AspNetCoreClassLibrary\AspNetCoreClassLibrary.csproj" />
</ItemGroup>

Resolving dependencies in ASP.Net Core can be done in three different ways – Transient, Scoped and Singleton.

Transient: A new instance will be created every time a call is made for that object.

Scoped: Only one instance will be created and served for every call made for the object in the same request.

Singleton: Only one instance will be created and served for every call made for the object for all request.

One has to be very careful in using any of the above type of services. If our logic is completely stateless, then we can go with Transient approach. If the logic has to hold certain data and configuration for the same HTTP Request and there is a possibility to invoke this service multiple times in the same HTTP Request, then scoped would be the right service type to be used. If the behavior of object is not going to change and it is going to be the same for all users and for all HTTP Requests, then singleton would be the apt approach.

In our tutorial, as we are using a static variable to hold the list of students, we will go with Singleton service. We will add following code in Startup.cs in ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IStudentOperations, StudentOperations>();
}

Now lets modify our controller to use the student operations instance which will be injected into constructor of controller.

using Microsoft.AspNetCore.Mvc;
using AspNetCoreClassLibrary;

namespace WebApplication3.Controllers
{
    [Route("api/[controller]")]
    public class StudentController : Controller
    {
        private IStudentOperations _studentOperations;
        public StudentController(IStudentOperations studentOperations)
        {
            _studentOperations = studentOperations;
        }
        // GET: api/Students
        [HttpGet(Name = "GetAllStudent")]
        public IActionResult Get()
        {
            return new ObjectResult(_studentOperations.GetAll());
        }

        // GET api/Student/5
        [HttpGet("{id}", Name = "GetStudent")]
        public IActionResult Get(int id)
        {
            return new ObjectResult(_studentOperations.GetById(id));
        }

        // POST api/student
        [HttpPost(Name = "CreateStudent")]
        public IActionResult Post([FromBody]Student student)
        {
            var _student = _studentOperations.Add(student);
            return CreatedAtRoute("GetStudent", new { id = _student.Id }, _student);
        }

        // PUT api/Student/5
        [HttpPut("{id}", Name = "UpdateStudent")]
        public IActionResult Put(int id, [FromBody]Student student)
        {
            var _student = _studentOperations.Update(id, student);
            return CreatedAtRoute("GetStudent", new { id = _student.Id }, _student);
        }

        // DELETE api/values/5
        [HttpDelete("{id}", Name = "DeleteStudent")]
        public IActionResult Delete(int id)
        {
            _studentOperations.Remove(id);
            return new NoContentResult();
        }
    }
}

NOTE: Instead of doing a constructor injection, we can also request a service from the HttpContext of current Request as shown below. This way of requesting a service is an Anti Pattern.

_studentOperations = Request.HttpContext.RequestServices.GetService<IStudentOperations>();

We can now run the solution and test all the API endpoints as shown in previous tutorial – CRUD Operations with ASP.Net Core Web API. I tested all the endpoints and results are exactly as shown in previous tutorial.

Create Operation

image

Read all Operation

image

Read specific Student

image

Update Student

image

Delete Operation

image

That’s it for now, we were able to inject dependencies at runtime using ASP.Net Core’s inbuilt DI Container. As a continuation of this tutorial, we can drive all the interfaces and implementations from an xml configuration file. I will write up another tutorial to demonstrate dependency injection through xml configuration.

Happy Coding and Stay Tuned!!!

You may also like...