---
sidebar_position: 2
title: DI & IOC
---

## Definition

When you have understood the fundamentals of object-oriented programming (OOP), you must quickly understand and assimilate several design patterns.

Indeed, this makes it possible to deal with known problems and thus to impose good practices which are based on the experience of software designers.

For me, and surely for many other software designers, one of the primary goals of design is to keep the interface clear, easily maintainable and above all scalable. As any developer knows, technologies evolve very very quickly.

This is why we are going to see dependency injection (DI) and inversion of control (Ioc).

### DI (Dependency Injection)

In C# it is simple to instantiate a new object via the “new” operator. Instantiating a new object into a class imposes a coupling (i.e. a tightly bound connection), or even a reference to an assembly.

We could get by if the project was not too complex with simple objects and very little coupling. But, let's say you want to create a service, how are you going to quickly implement it in a new class/assembly? And in the worst case, the day you want to change the type of service in your simple project, which over time has become complex, how are you going to proceed?

As you have understood, this pattern is for any developer who cares about the quality of his software and seeks to make his application as maintainable as possible.

Indeed, the injection makes it possible to establish in a dynamic way the relation between several classes. It consists in dividing the responsibilities between the different modules, the different parts and even facilitates the subsequent modification of the classes.

### IOC (Inversion Of Control)

Once we have understood the principle of dependency injection, we can tackle another higher-level concept: inversion of control.

Indeed, if we have few or many classes calling on our service, we will create upstream `IMyService` instances as many times as necessary.
So we will end up with multiple instances, which was not meant to happen. Also, the fact of instantiating our interface in several places, we will find ourselves faced with as much code duplication as instantiations, which will make our application difficult to maintain.

Therefore, the first idea that comes to mind when we are unfamiliar with dependency inversion is to make our `MyService` class static.
Which is a very bad idea. We no longer have any problem with instances, however, now we will have to make our class `thread-safe` and properly manage `multi-threading`.
Not to mention the problems we will face when we want to do unit tests.

Others will have thought of the `singleton`. This is not the case, there are often too many memory leak problems.

Then, when we look in its fundamentals, we naturally think of one of the design patterns described by the "Gof": the `Factory`.

Indeed, a factory with a singleton could be the solution, unfortunately, there would always remain a weak coupling between the class and the call to each factory.

In our example, we would only have one, so we don't see the point of it.
But, in an application there are far more factories and there would therefore be as many couplings as there are factories. Without counting on the instantiations which can be more or less long.
But under certain conditions we could see it immediately without having to wait for the instantiation time.

To be able to outsource even more code, such as the creation of our object, and not slow down our program if there are long instantiations, we are going to have to map the contracts with their implementations at the start of the application.

The IOC is defined as a container that determines what must be instantiated and returned to the client to prevent the latter from explicitly calling the constructor with the "new" operator.

In a nutshell, it's an object that acts as a cache for the instances we need in various parts of our applications.

## Add services to a Blazor Server app

After creating a new app, examine part of the `Program.cs` file:

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
```

The `builder` variable represents a `Microsoft.AspNetCore.Builder.WebApplicationBuilder` with an `IServiceCollection`, which is a list of service descriptor objects. 
Services are added by providing service descriptors to the service collection. 

The following example demonstrates the concept with the `IDataAccess` interface and its concrete implementation `DataAccess`:

```csharp
builder.Services.AddSingleton<IDataAccess, DataAccess>();
```

## Service lifetime

Services can be configured with the following lifetimes:

### `Scoped`

Blazor WebAssembly apps don't currently have a concept of DI scopes. `Scoped`-registered services behave like `Singleton` services.

The Blazor Server hosting model supports the `Scoped` lifetime across HTTP requests but not across SignalR connection/circuit messages among components that are loaded on the client. The Razor Pages or MVC portion of the app treats scoped services normally and recreates the services on each HTTP request when navigating among pages or views or from a page or view to a component. Scoped services aren't reconstructed when navigating among components on the client, where the communication to the server takes place over the SignalR connection of the user's circuit, not via HTTP requests. In the following component scenarios on the client, scoped services are reconstructed because a new circuit is created for the user:

* The user closes the browser's window. The user opens a new window and navigates back to the app.
* The user closes a tab of the app in a browser window. The user opens a new tab and navigates back to the app.
* The user selects the browser's reload/refresh button.

### `Singleton`

DI creates a single instance of the service. All components requiring a `Singleton` service receive the same instance of the service.

### `Transient`

Whenever a component obtains an instance of a `Transient` service from the service container, it receives a new instance of the service.

## Request a service in a component

After services are added to the service collection, inject the services into the components using the @inject Razor directive, which has two parameters:

* Type: The type of the service to inject.
* Property: The name of the property receiving the injected app service. The property doesn't require manual creation. The compiler creates the property.


Use multiple `@inject` statements to inject different services.

The following example shows how to use `@inject`. 

The service implementing `Services.IDataAccess` is injected into the component's property `DataRepository`. Note how the code is only using the `IDataAccess` abstraction:

```csharp
@page "/customer-list"
@inject IDataAccess DataRepository

@if (customers != null)
{
    <ul>
        @foreach (var customer in customers)
        {
            <li>@customer.FirstName @customer.LastName</li>
        }
    </ul>
}

@code {
    private IReadOnlyList<Customer>? customers;

    protected override async Task OnInitializedAsync()
    {
        customers = await DataRepository.GetAllCustomersAsync();
    }

    private class Customer
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
    }

    private interface IDataAccess
    {
        public Task<IReadOnlyList<Customer>> GetAllCustomersAsync();
    }
}
```

Internally, the generated property (`DataRepository`) uses the `[Inject]` attribute. 
Typically, this attribute isn't used directly. 
If a base class is required for components and injected properties are also required for the base class, manually add the `[Inject]` attribute:

```csharp
using Microsoft.AspNetCore.Components;

public class ComponentBase : IComponent
{
    [Inject]
    protected IDataAccess DataRepository { get; set; }

    ...
}
```

## Use DI in services

Complex services might require additional services. 

In the following example, `DataAccess` requires the HttpClient default service. `@inject` (or the `[Inject]` attribute) isn't available for use in services. 
Constructor injection must be used instead. 
Required services are added by adding parameters to the service's constructor. 
When DI creates the service, it recognizes the services it requires in the constructor and provides them accordingly. 

In the following example, the constructor receives an `HttpClient` via DI. `HttpClient` is a default service.

```csharp
using System.Net.Http;

public class DataAccess : IDataAccess
{
    public DataAccess(HttpClient http)
    {
        ...
    }
}
```

Prerequisites for constructor injection:

* One constructor must exist whose arguments can all be fulfilled by DI. Additional parameters not covered by DI are allowed if they specify default values.
* The applicable constructor must be public.
* One applicable constructor must exist. In case of an ambiguity, DI throws an exception.

