How to configure Dependency Injection in ASP.NET Core application?

If you are using ASP.NET Core framework to build your web application, you will be happy to know that with ASP.NET Core, Dependency Injection (DI) is now a first class citizen in ASP.NET. The same DI container is used by the whole ASP.NET stack as well as your application code. In this post, I’ll tell you how to configure Dependency Injection in ASP.NET Core application.

In simple words, Dependency Injection (DI), is a type of IoC where the creation and binding of a dependency is moved outside of the class that depends on it.

Say suppose when you pack your lunch, you know what you have packed inside it. But when you know that the food will be provided, you know that you need not to worry about lunch, it will just be served when you need it.

Example

Below is the definition of Product, ProductService class that implements an interface named IProductService. This service is responsible to provide products to the consumer within the application.

The idea behind this service implementing this interface is that our application can use the interface for reference and the actual implementation will be available at run-time with the magic of DI container.

Implementation of Product service class and IProductService interface

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

publicclassProduct

{

publicintId{get;set;}

publicstringName{get;set;}

publicstringDescription{get;set;}

publicdoublePrice{get;set;}

}

publicinterfaceIProductService

{

IEnumerable<Product>GetAll();

}

publicclassProductService

{

publicIEnumerable<Product>GetAll()

{

// get data from database or request it from another service using REST, etc.

returnnewList<Product>();

}

}

Register the service(s)

We need to add this ProductService to the DI container first so that application can consume it on demand with the help of just referring IProductService type. The file named Startup.cs has a method named ConfigureServices where this needs to be done.

We have access to IServiceCollection services in this method that has important methods mentioned below. The basic idea is to map the interface type to the concrete type definition. Anytime your application requests an instance of concrete type, an instance will be provided by using the DI container. This instance can be shared, new or scope within the application which depends on how the type is mapped with IServiceCollection services.

If AddTransient or ServiceLifeTime.Transientis used then a new instance of the mapped type is available to the consumer.

If AddSingleton or ServiceLifeTime.Singletonis used then a shared instance of the mapped type is available to the consumer.

If AddScoped or ServiceLifeTime.Scopedis used then a scoped instance of the mapped type is available to the consumer. Scoped in this case means scoped to an HTTP request i.e. this instance will be singleton while the current request is in scope.

You may also add an existing instance to the DI container using the method AddInstance.

Extension to the rescue

There can be many mapping statements like this for registration process, in this case you should create an extension method to the IServiceCollection to keep your method and file clean. An example of this is how we add MVC to the container, e.g. services.AddMvc();

A custom extension to add logically grouped services to the IServiceCollection services needed by the middleware will look similar to this:

A custom extension to register services.

C#

1

2

3

4

5

6

7

8

9

10

11

publicstaticclassServiceCollectionExtensions

{

publicstaticIServiceCollection RegisterServices(

thisIServiceCollection services)

{

services.AddTransient<IProductService,ProductService>();

// and a lot more Services

returnservices;

}

}

Now the method ConfigureServices looks much more cleaner and thin:

ConfigureServices method definition

C#

1

2

3

4

5

6

7

publicvoidConfigureServices(IServiceCollection services)

{

// Add framework services.

services.AddMvc();

services.RegisterServices();

}

Usage

A mapped service with the container can be requested in the application very easily.

For example, to request an instance of ProductService in controller, all we need to write is following:

Request an instance of service registered with container

C#

1

2

3

4

5

6

7

8

9

10

publicclassHomeController:Controller

{

privatereadonlyIProductService _productService;

publicHomeController(IProductService productService)

{

_productService=productService;

}

// …

}

We can also request an instance inside a View like this:

Inject an instance of a service in view

C#

1

@inject Services.IProductService productService;

The statement above is simple, the first part after the @inject directive defines the interface. The second part is the name of the variable which will hold the instance.

This is good for per view basis but to inject a service globally into all Views, we just need to move this statement to the _ViewImports.cshtml file. An example of a global injection defined for ApplicationInsights is:

Finally, we can use the variable in our view just like any other variable as shown below:

Use ProductService class instance in view

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@if(productService.All().Any())

{

<ul>

@foreach(varproduct inproductService.All().OrderBy(x=>x.Name))

{

<p>@product.Name(@product.Description)</p>

}

</ul>

}

@Html.DropDownList("Products",productService.All()

.OrderBy(x=>x.Name)

.Select(x=>newSelectListItem

{

Text=x.Name,

Value=x.Id

}))

Just for your information, DI also works in MiddleWares, TagHelpers and ViewComponents.

Conclusion

You can use DI container almost anywhere in the application (except in HTMLHelpers, because these are extension methods) for custom services as well as services registered by ASP.NET Core. This helps to keep application clean, light-weight (no need of any other DI container implementation), maintainable and testable. Hope this post easily explains how to configure Dependency Injection in ASP.NET Core application.

Siddharth Pandey is a Software Engineer with thorough hands-on commercial experience & exposure to building enterprise applications using Agile methodologies. Siddharth specializes in building, managing on-premise, cloud based real-time standard, single page web applications (SPAs). He has successfully delivered applications in health-care, finance, insurance, e-commerce sectors for major brands in the UK. Other than programming, he also has experience of managing teams, trainer, actively contributing to the IT community by sharing his knowledge using Stack Overflow, personal website & video tutorials.