# Dependency Injection

ASP.NET Core includes [*dependency injection*](#user-content-fn-1)[^1] that makes configured services available throughout an app. Services are added to the DI container with `WebApplicationBuilder.Services`.

> ASP.NET Core provides a built-in service container, `IServiceProvider`, in which any dependency[^2] can be registered.

<pre class="language-csharp" data-title="Program.cs"><code class="lang-csharp">using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;

<strong>var builder = WebApplication.CreateBuilder(args);
</strong>var connectionStr = builder.Configuration.GetConnectionString("DefaultConnection");

// Add services to the container.
<strong>builder.Services.AddRazorPages();
</strong><strong>builder.Services.AddControllersWithViews();
</strong>
builder.Services.AddDbContext&#x3C;ApplicationDbContext>(options =>
   options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity&#x3C;IdentityUser>(options => 
   options.SignIn.RequireConfirmedAccount = true)
   .AddEntityFrameworkStores&#x3C;ApplicationDbContext>();

var app = builder.Build();
</code></pre>

* Services are typically resolved from DI using **constructor injection**. The DI framework provides an instance of this service at runtime.

> *Injection* of the service into the constructor of the class where it's used. The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

<pre class="language-csharp"><code class="lang-csharp">public class IndexModel : PageModel {
<strong>    private readonly RazorPagesMovieContext _context;
</strong><strong>    private readonly ILogger&#x3C;IndexModel> _logger;
</strong><strong>
</strong><strong>    public IndexModel(RazorPagesMovieContext context, ILogger&#x3C;IndexModel> logger) {
</strong><strong>        _context = context;
</strong><strong>        _logger = logger;
</strong><strong>    }
</strong>
    public IList&#x3C;Movie> Movie { get;set; }

    public async Task OnGetAsync() {
<strong>        _logger.LogInformation("IndexModel OnGetAsync.");
</strong><strong>        Movie = await _context.Movie.ToListAsync();
</strong>    }
}
</code></pre>

{% hint style="info" %}
In dependency injection terminology, a service:

* Is typically an object that provides a service to other objects, such as the `IMyDependency` service.
* Is not related to a web service, although the service may use a web service.
  {% endhint %}

{% hint style="info" %}
`IServiceCollection` - register services

`IServiceProvider` - resolve service instances
{% endhint %}

## Service Lifetimes

> * *Transient* objects are always different.
> * *Scoped* objects are the same for a given request but differ across each new request.
> * *Singleton* objects are the same for every request.

* The container calls `Dispose()` for the `IDisposable` types it creates. Services resolved from the container should never be disposed by the developer. If a type or factory is registered as a singleton, the container disposes the singleton automatically.

{% tabs %}
{% tab title="Services.cs" %}

```csharp
public class Service1 : IDisposable {
    private bool _disposed;

    public void Write(string message) {
        Console.WriteLine($"Service1: {message}");
    }

    public void Dispose() {
        if (_disposed)
            return;

        Console.WriteLine("Service1.Dispose");
        _disposed = true;
    }
}

public class Service2 : IDisposable {
    private bool _disposed;

    public void Write(string message) {
        Console.WriteLine($"Service2: {message}");
    }

    public void Dispose() {
        if (_disposed)
            return;

        Console.WriteLine("Service2.Dispose");
        _disposed = true;
    }
}

public interface IService3 {
    public void Write(string message);
}

public class Service3 : IService3, IDisposable {
    private bool _disposed;
    public string MyKey { get; }

    public Service3(string myKey) {
        MyKey = myKey;
    }

    public void Write(string message) {
        Console.WriteLine($"Service3: {message}, MyKey = {MyKey}");
    }

    public void Dispose() {
        if (_disposed)
            return;

        Console.WriteLine("Service3.Dispose");
        _disposed = true;
    }
}
```

{% endtab %}

{% tab title="Program.cs" %}

```csharp
using DIsample2.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddScoped<Service1>();
builder.Services.AddSingleton<Service2>();

var myKey = builder.Configuration["MyKey"];
builder.Services.AddSingleton<IService3>(sp => new Service3(myKey));

var app = builder.Build();
```

{% endtab %}

{% tab title="IndexModel.cs" %}

```csharp
public class IndexModel : PageModel
{
    private readonly Service1 _service1;
    private readonly Service2 _service2;
    private readonly IService3 _service3;

    public IndexModel(Service1 service1, Service2 service2, IService3 service3)
    {
        _service1 = service1;
        _service2 = service2;
        _service3 = service3;
    }

    public void OnGet()
    {
        _service1.Write("IndexModel.OnGet");
        _service2.Write("IndexModel.OnGet");
        _service3.Write("IndexModel.OnGet");
    }
}
```

{% endtab %}

{% tab title="Output" %}

```
Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet
Service1.Dispose
```

{% endtab %}
{% endtabs %}

* The service instances that aren't created by the service container, The framework doesn't dispose these services automatically. The developer is responsible for disposing the services.

* High-level modules should not depend on low-level modules.

* Abstraction should not depend upon details

* Modules and Details should depend upon abstraction.

#### Benefits of Dependency Injection

* promotes loose coupling of components
* promotes logical abstraction of components
* supports unit testing

**How to find dependency?**

1. Locate 'new' keyword usage
2. is the object a dependency?
3. apply dependency inversion
4. register the service
5. rinse and repeat

| AddTransient                                                  | AddScoped                                         | AddSingleton                                                                   |
| ------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------ |
| instance of services are created each time they are requested | instance of services are created once per request | instance of services are created only once, the first time they were requested |

### Understanding Service Lifetime

Built-in IoC container manages the lifetime of a registered service type. It automatically disposes a service instance based on the specified lifetime.

The built-in IoC container supports three kinds of lifetimes:

1. **Singleton:** IoC container will create and share a single instance of a service throughout the application's lifetime. \
   or, once for the lifetime of the application.
2. **Transient:** The IoC container will create a new instance of the specified service type every time you ask for it.\
   or, each time they are requested.
3. **Scoped:** IoC container will create an instance of the specified service type once per request and will be shared in a single request.\
   or, once per request

{% code title="Registering Services " %}

```aspnet
public void ConfigureServices(IServiceCollection services)
{
    services.Add(new ServiceDescriptor(typeof(ILog), new MyConsoleLogger()));    // singleton
    
    services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), ServiceLifetime.Transient)); // Transient
    
    services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), ServiceLifetime.Scoped));    // Scoped
}
```

{% endcode %}

{% code title="Extension Methods" %}

```aspnet
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ILog, MyConsoleLogger>();
    services.AddSingleton(typeof(ILog), typeof(MyConsoleLogger));

    services.AddTransient<ILog, MyConsoleLogger>();
    services.AddTransient(typeof(ILog), typeof(MyConsoleLogger));

    services.AddScoped<ILog, MyConsoleLogger>();
    services.AddScoped(typeof(ILog), typeof(MyConsoleLogger));
}
```

{% endcode %}

### Constructor Injection

Once we register a service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor.

{% code title="Constructor Injection" %}

```csharp
public class HomeController : Controller
{
    ILog _log;
    public HomeController(ILog log)
    {
        _log = log;
    }
    public IActionResult Index()
    {
        _log.info("Executing /home/index");
        return View();
    }
}
```

{% endcode %}

### Action Method Injection

Sometimes we may only need dependency service type in a single action method. For this, use `[FromServices]` attribute with the service type parameter in the method.

{% code title="Action Method Injection" %}

```csharp
using Microsoft.AspNetCore.Mvc;

public class HomeController : Controller
{
    public HomeController()
    {
        //some code
    }

    public IActionResult Index([FromServices] ILog log)
    {
        log.info("Index method executing");

        return View();
    }
}
```

{% endcode %}

### Get Services Manually

It is not required to include dependency services in the constructor. We can access dependent services configured with built-in IoC container manually using `RequestServices` property of `HttpContext`&#x20;

```csharp
public class HomeController : Controller
{
    public HomeController()
    {
    }
    public IActionResult Index()
    {
        var services = this.HttpContext.RequestServices;
        var log = (ILog)services.GetService(typeof(ILog));
            
        log.info("Index method executing");
    
        return View();
    }
}
```

[^1]: Dependency Injection (DI), a technique for achieving **Inversion of Control (IoC)** between classes and their dependencies.

[^2]: A *dependency* is an object that another object depends on.
