How YOU can Learn Dependency Injection in .NET Core and C#
Tags: dotnet, tutorial, webdev, csharp
Published: 2019-11-28 00:47:27

---
title: How YOU can Learn Dependency Injection in .NET Core and C#
published: true
description: This gives an introduction to Dependency Injection in general but also to how to use it in .NET Core
tags: dotnet, tutorial, webdev, csharp
cover_image: https://thepracticaldev.s3.amazonaws.com/i/69mlfxzpei2p9ggc0xls.jpg
canonical_url: https://softchris.github.io/pages/dotnet-di.html
---

Follow me on [Twitter](https://twitter.com/chris_noring), happy to take your suggestions on topics or improvements /Chris



This is an intro to Dependency Injection, also called DI. I plan a follow-up post covering more advanced scenarios. For now, I want to explain what it is and how you can use it and finally show how it helps to test A LOT.

## What is Dependency Injection

It's a programming technique that makes a class independent of its dependencies. 

> English?

We don't rely on a concrete implementation of our dependencies, but rather interfaces. This makes our code more flexible and we can easily switch out a concrete implementation for another while maintaining the same logic.

## References

- [Overview of Dependency Injection](https://docs.microsoft.com/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0&wt.mc_id=devto-blog-chnoring)
- [DI MVC example](https://docs.microsoft.com/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-3.0&wt.mc_id=devto-blog-chnoring)
- [DI in Controllers](https://docs.microsoft.com/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-3.0&wt.mc_id=devto-blog-chnoring)
- [Dependency Injection pattern by Martin Fowler](https://www.martinfowler.com/articles/injection.html)
- [Overview of Dependency Injection namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection?view=dotnet-plat-ext-3.0&wt.mc_id=devto-blog-chnoring)

## Why use it

There are many advantages:

- **Flexible code**, we can switch out one implementation for another without changing the business logic.
- **Easy to test**, because we rely on interfaces over implementations - we can more easily test our code without worrying about side-effects. We will show this later in the article.

## DI in .NET Core - it's built-in

There's a built-in Dependency Injection container that's used by a lot of internal services like:

- Hosting Environment
- Configuration
- Routing
- MVC
- ApplicationLifetime
- Logging

The container is sometimes referred to as IoC, **I**nversion of **C**ontrol **C**ontainer.

The overall idea is to *Register* at the application startup and then *Resolve* at runtime when needed.

Container responsibilities:
- Creating
- Disposing
- **IServiceCollection**, Register services, lets the IoC container know of concrete implementation. It should be used to resolve what Interface belongs to what implementation. How something is created can be as simple as just instantiating an object but sometimes we need more data than that.
- **IServiceProvider**, Resolve service instances, actually looking up what interface belongs to what concrete implementation and carry out the creation.

It lives in the `Microsoft.Extensions.DependencyInjection`.

### What to register

There are some telltale signs. 

- **Lifespan outside of this method?**, Are we *new-ing* the service, any services that can they live within the scope of the method? I.e are they a dependency or not?
- **More than one version**, Can there be more than one version of this service?
- **Testability**, ideally you only want to test a specific method. If you got code that does a lot of other things in your method, you probably want to move that to a dedicated service. This moved code would then become dependencies to the method in question
- **Side-effect**, This is similar to the point above but it stresses the importance of having a method that does only one thing. If a side-effect is produced, i.e accessing a network resource, doing an HTTP call or interacting with I/O - then it should be placed in a separate service and be injected in as a dependency. 

Essentially, you will end up moving out code to dedicated services and then inject these services as dependencies via a constructor. You might start out with code looking like so:

```csharp
public void Action(double amount, string cardNumber, string address, string city, string name) 
{
  var paymentService = new PaymentService();
  var successfullyCharged = paymentService.Charge(int amount, cardNumber);

  if (successfullyCharged) 
  {
    var shippingService = new ShippingService();
    shippingService.Ship(address, city, name);
  }
}
```

The above has many problems: 

- **Unwanted side-effects when testing**, The first problem is that we control the lifetime of `PaymentService` and `ShippingService`, thus risking firing off a side-effect, an HTTP call, when trying to test.
- **Can't test all paths**, we can't really test all paths, we can't ask the PaymentService to respond differently so we can test all execution paths
- **Hard to extend**, will this PaymentService cover all the possible means of payment or would we need to add a lot of conditional code in this method to cover different ways of taking payment if we added say support for *PayPal* or a new type of card, etc?
- **Unvalidated Primitives**, there are primitives like `double` and `string`. Can we trust those values, is the `address` a valid address for example? 

From the above, we realize that we need to refactor our code into something more maintainable and more secure. Turning a lot of the code into dependencies and replacing primitives with more complex constructs - is a good way to go.

The result could look something like this:

```csharp
class Controller 
  private readonly IPaymentService _paymentService;
  private readonly IShippingService _shippingService;

  public void Controller(
    IPaymentService paymentService,
    IShippingService shippingService
    ) 
  {
    _paymentService = paymentService;
    _shippingService = shippingService;
  }

  public void Action(IPaymentInfo paymentInfo, IShippingAddress shippingAddress) 
  {
    var successfullyCharged = _paymentService.Charge(paymentInfo);

    if (successfullyCharged) 
    {
      _shippingService.Ship(ShippingAddress);
    }
  }
}
```

Above we have turned both the `PaymentService` and `ShippingService` into dependencies that we inject in the constructor. We also see that all the primitives have been collected into the complex structures `IShippingAddress` and `IPaymentInfo`. What remains is pure business logic. 

### Dependency Graph

When you have a dependency it might itself rely on another dependency being resolved first and so on and so forth. This means we get a hierarchy of dependencies that need to be resolved in the right order for things to work out. We call this a *Dependency Graph*. 

## DEMO - registering a Service

We will do the following:

- **create** a .NET Core solution
- **add** a webapi project to our solution
- **fail**, see what happens if we forgot to register a service. It's important to recognize the error message so we know where we went wrong and can fix it
- **registering a service**, we will register our service and we will now see how everything works

### Create a solution

```
mkdir di-demo
cd di-demo

dotnet new sln
```

this will create the following structure:

```
-| di-demo
---| di-demo.sln
```

### Create a WebApi project

```
dotnet new webapi -o api
dotnet sln add api/api.csproj
```

The above will create a `webapi` project and add it to our solution file. 

Now we have the following structure:

```
-| di-demo
---| di-demo.sln
---| api/
```

### fail

First, we will compile and run our project so we type: 

```
dotnet run
```

The first time you run the project the web browser might tell you something like *your connection is not secure*. You have a dev cert that's not trusted. Fortunately, there's a built-in tool that can fix this so you can run a command like this:

```
dotnet dev-certs https --trust
```

For more context on the problem:

> https://www.hanselman.com/blog/DevelopingLocallyWithASPNETCoreUnderHTTPSSSLAndSelfSignedCerts.aspx

You should have something like this running:

![](https://thepracticaldev.s3.amazonaws.com/i/tqejf0xhgfhuf35vo1eh.png)

Ok then, we don't have an error but let's introduce one. 

Let's do the following:

1. **Create a controller** that supports getting products, this should inject a `ProductsService`
2. **Create a ProductsService**, this should be able to retrieve Products from a data source
3. **Create a IProductsService interface, inject this interface in the controller

**Add a ProductsController**

Add the file `ProductsController.cs` with the following content:

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Services;

namespace api.Controllers
{
  [ApiController]
  [Route("[controller]")]
  public class ProductsController : ControllerBase
  {
    private readonly IProductsService _productsService;
    public ProductsController(IProductsService productsService) {
      _productsService = productsService;
    }

    [HttpGet]
    public IEnumerable<Product> GetProducts() 
    {
      return _productsService.GetProducts();
    }
  }
}
```

Note how we *inject* the `IProductsService` in the constructor. This file should be added to the `Controllers` directory.

**Add a ProductsService**

Let's create a file `ProductsService.cs` under a directory `Services`, with the following content:

```csharp
using System;
using System.Collections.Generic;
using System.Linq;

namespace Services {
  public class Product {
    public string Title { get; set; }
  }

  public class ProductsService: IProductsService 
  {
    private readonly List<Product> Products = new List<Product> 
    { 
      new Product { Title= "DVD player" },
      new Product { Title= "TV" },
      new Product { Title= "Projector" }
    };

    public IEnumerable<Product> GetProducts() 
    {
      return Products.AsEnumerable();
    }
  }
}
```

**Create an interface IProductsService**

Let's create the file `IProductsService.cs` under the `Services` directory, with the following content:

```csharp
using System;
using System.Collections.Generic;

namespace Services 
{
  public interface IProductsService
  {
      IEnumerable<Product> GetProducts();
  }
}
```

**Run**

Let's run the project with:

```
dotnet build
dotnet run
```

We should get the following response in the browser:

![](https://thepracticaldev.s3.amazonaws.com/i/p5163j4fxgq8qq6o6by6.png)

It's failing, just like we planned. Now what?

Well, we fix it, by registering it with our container.

### Registering a service

Ok, let's fix our problem. We do so by opening up the file `Startup.cs` in the project root. Let's find the `ConfigureServices()` method. It should have the following implementation currently:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}
```

Let's change the code to the following:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IProductsService, ProductsService>();
    services.AddControllers();
}
```

The call to `services.AddTransient()` registers `IProductsService` and associates it with the implementing class `ProductsService`. If we run our code again:

```
dotnet run
```

Now your browser should be happy and look like this:

![](https://thepracticaldev.s3.amazonaws.com/i/tobp1d7nis6v2yfwdbkz.png)

> Do we know all we need to know now?

No, there's lots more to know. So please read on in the next section to find out about different lifetimes, *transient* is but one type of lifetime type.


## Service lifetimes

The service life time means how long the service will live, before it's being garbage collected. There are currently three different lifetimes:

- **Transient**, `services.AddTransient()`, the service is created each time it is requested
- **Singleton**, `services.AddSingleton()`, created once for the lifetime of the application
- **Scoped**, `services.AddScoped()`, created once per request 

> So when to use each kind?

Good question. 

### Transient

So for Transient, it makes sense to use when you have a mutable state and it's important that the service consumer gets their own copy of this service. Also when thread-safety is not a requirement. This is a good *default* choice when you don't know what life time to go with.

### Singleton

Singleton means that we have one instance for the lifetime of the application. This is good if we want to share state or creating the Service is considered expensive and we want to create it only once. So this can boost performance as it's only created once and garbage collected once. Because it can be accessed by many consumers thread-safety is a thing that needs to be considered. A good use case here is a memory cache but ensure you are making it thread-safe. Read more here about how to make something *thread-safe*:

> http://www.albahari.com/threading/part2.aspx

Read especially about the `lock` keyword in the above link.

### Scoped

Scoped means it's created once per request. So all calling consumers within that request will get the same instance. Examples of scoped services are for example `DbContext` for Entity Framework. It's the class we use to access a Database. It makes sense to make it *scoped*. We are likely to do more than one call to it during our request and the resource should be scoped to that specific request/user.

### Here be dragons

There's such a thing as *captured dependencies*. This means that a service lives longer than expected. 

> So why is that bad? 

Well, you want services to live according to their lifetime, otherwise, we take up unnecessary space in memory.

> How does it happen?

When you start depending on a Service with a shorter lifetime than yourself you are effectively *capturing* it, forcing it to stay around according to your lifetime. Example: 

You register a `ProductsService` with a scoped lifetime and an `ILogService` with a transient lifetime. Then you inject the `ILogService` into the `ProductsService` constructor and thereby *capturing* it. 

```
class ProductsService 
{
  ProductsService(ILogService logService) 
  {

  }
}
```

> Don't do that!

If you are going to depend on something ensure that what you inject has an equal or longer life time than yourself. So either change what you depend on or change the lifetime of your dependency. 

## Summary

We have explained what Dependency Injection is and why it's a good idea to use it. Additionally, we have shown how the built-in container helps us register our dependencies. Lastly, we've discussed how there are different lifetimes for a dependency and which one we should be choosing. 

This was the first part of the built-in container. I hope you are excited about a follow-up post talking about some of its more advanced features.