Dependency injection in ASP .NET Core Web API

Marek Balaz
4 min readNov 2, 2022

--

Hello mates, in this tutorial, we are going to look at popular software design pattern called Dependency injection. If you don’t know, what dependency injection does, keep calm and keep reading. I chose practical and interesting task in order to motivate your learning.

Task specification

Write an ASP .NET Core Web API application to get the daily price of bitcoin. So the use case is simple — the user sends a GET request to the API and then obtains the bitcoin exchange rate (BTC/USD).

Project initialization

  • Step 1: Create a new ASP .NET Core Web API project in Visual Studio (set project name and solution name to PriceProjectAPI)
  • Step 2: Delete WeatherForecastController.cs and WeatherForecast.cs
  • Step 3: Create new folders PriceProjectAPI/Logic and PriceProjectAPI/Logic/BitcoinProvider (for simplicity, I decided to implement business logic into the same project as API controllers)

Bitcoin data

I don’t like tutorials in which you must to sign up to third party APIs to use some trials… Therefore, I found a FREE API endpoint that provides a daily bitcoin exchange rate - https://api.coindesk.com/v1/bpi/currentprice.json

CoinDesk provider

Let’s start with the implementation of the class CoinDeskProvider.cs (create a new class in PriceProjectAPI/Logic/BitcoinProvider/). The class contains only one method — GetPrice without parameters. As you probably know, the decimal type is used for financial data (it has more accuracy). Therefore, the method should return decimal type. Method downloads JSON from CoinDesk API (via WebClient) and parses BTC/USD price (via JsonDocument).

Bitcoin controller (wrong implementation)

In this subsection, I am going to show you the wrong implementation of the bitcoin controller. Create a new controller — BitcoinPriceController.cs (in PriceProjectAPI/Controller). The controller consists of the attribute _bitcoinProvider. The provider is used in the GET method GetPrice in which the current bitcoin price is returned.

As you can see, the provider is directly initialized in the controller constructor. So there is a direct dependency between the controller and the business logic class. In the future, CoinDesk may disable this API endpoint, so you will have to find a new option. In this case, you will need to implement a new bitcoin price provider and update your controller by replacing the broken provider with a new one. Replacing old components with new ones in the controller is a waste of work that causes incorrect software design.

Wrong design (look at direct dependency)

Interface IBitcoinProvider

The best way to prevent this problem is to use abstraction as an abstract class or interface. Our provider contains only one method. Therefore, we are going to implement an interface with the method GetPrice (create a new interface in path PriceProjectAPI/Logic/BitcoinProvider/IBitcoinProvider).

Don’t forget to add the interface into CoinDeskProvider.cs

Bitcoin controller (better implementation)

Let’s add an abstraction to our BitcoinPriceController via an interface. The first step is to replace the type of the IBitcoinProvider attribute. In the second step, we replace directly initialization of the attribute (_bitcoinProvider = new CoinDeskProvider()) with a new constructor parameter (bitcoinProvider).

Better design

As you can see in the controller code or in the class diagram, the controller doesn’t know anything about the specific CoinDeskProvider. We are now able to implement a new bitcoin provider and replace the old one without any controller changes. Remember that abstraction is your friend because it helps you keep your code clean and saves you time.

This controller modification is called a dependency inversion (not injection) technique, in which the connection between a higher-level class (controller) and a lower-level class (concrete provider) is replaced by using an abstraction (abstract class or interface).

Dependency injection

After using the dependency inversion technique, we should implement dependency injection. In short, dependency injection passes (injects) concrete objects (instances) to parameters instead of hard-coding them in the class. Many developers consider dependency inversion and dependency injection to be the same technique. However, dependency inversion does not manage how to pass arguments.

In ASP .NET Core, dependency injection is solved via Inversion of Control (IoC). IoC creates an object of a specific class and passes it as an argument to a constructor or method. So in our case, whenever the user calls the bitcoin controller, the IoC is called before to create and pass the required object to the constructor.

IoC also controls the lifetime of created objects. In some cases, it is better to create a new object for each request. Other times you want to keep a lifetime instance. In our case, we will create a new instance for each request.

The final step is to define which instance to create for the IBitcoinProvider interface. Each definition is registered as a new service in Program.cs. On line 6, we register this definition using the AddTransient method. We define the abstraction and class of a specific object through generics such as <IBitcoinProvider, CoinDeskProvider>.

The second approach is to register a specific object class with some arguments. In this case, you can use the lambda function.

To use a lifetime instance, you must use the AddSingleton method. The last option is to use AddScoped to achieve the lifetime scope.

Now you can use Swagger to find out the price of bitcoins. That’s all, thank you for your attention and keep improving your skills! :)

--

--

Marek Balaz

C# software developer and fan of programming techniques