---
title: Dependency Injection (Controllers)
description: Hướng dẫn chi tiết về Dependency Injection trong ASP.NET Core MVC — Constructor Injection, Action Injection, Keyed Services và Options Pattern.
---

## Dependency Injection là gì?

ASP.NET Core MVC controllers request dependencies một cách **explicit** thông qua constructors. ASP.NET Core có **built-in support** cho dependency injection (DI). DI giúp ứng dụng **dễ test** và **dễ bảo trì**.

```mermaid
flowchart TD
    A["🎮 Controller"] --> B["🔧 Constructor"]
    B --> C["📦 DI Container"]
    C --> D["🛠️ Services"]
    D --> B
```

---

## Constructor Injection

### Nguyên tắc cơ bản

Services được thêm như **constructor parameters**, và runtime resolve service từ service container. Services thường được định nghĩa dùng **interfaces**.

### Ví dụ: Interface và Implementation

```csharp
public interface IDateTime
{
    DateTime Now { get; }
}

public class SystemDateTime : IDateTime
{
    public DateTime Now => DateTime.Now;
}
```

### Đăng ký Service

```csharp
public void ConfigureServices(IServiceCollection services)
{
    // Đăng ký service với DI container
    services.AddSingleton<IDateTime, SystemDateTime>();

    services.AddControllersWithViews();
}
```

### Controller sử dụng Constructor Injection

```csharp
public class HomeController : Controller
{
    private readonly IDateTime _dateTime;

    // Service được inject tự động qua constructor
    public HomeController(IDateTime dateTime)
    {
        _dateTime = dateTime;
    }

    public IActionResult Index()
    {
        var serverTime = _dateTime.Now;
        if (serverTime.Hour < 12)
        {
            ViewData["Message"] = "Chào buổi sáng!";
        }
        else if (serverTime.Hour < 17)
        {
            ViewData["Message"] = "Chào buổi chiều!";
        }
        else
        {
            ViewData["Message"] = "Chào buổi tối!";
        }
        return View();
    }
}
```

> **Lưu ý:** Services thường được đăng ký dùng **interfaces** để:
>
> - Giảm coupling giữa controller và implementation
> - Dễ thay thế implementation trong unit tests (mock)
> - Tăng tính modular của ứng dụng

---

## Action Injection với `[FromServices]`

### Khi nào dùng

Action injection hữu ích khi service chỉ cần cho **một action duy nhất**, không cần dùng ở nhiều action.

```csharp
public class HomeController : Controller
{
    [FromServices]
    public IDateTime DateTime { get; set; }

    public IActionResult About()
    {
        return Content($"Thời gian hiện tại: {DateTime.Now}");
    }
}
```

### So sánh Constructor vs Action Injection

| Tiêu chí        | Constructor Injection           | Action Injection           |
| --------------- | ------------------------------- | -------------------------- |
| **Phạm vi**     | Tất cả actions trong controller | Chỉ action được chỉ định   |
| **Tái sử dụng** | ✅ Cao                          | ❌ Thấp                    |
| **Đăng ký**     | Một lần                         | Mỗi action                 |
| **Dùng khi**    | Nhiều actions cần service       | Chỉ một action cần service |

---

## Keyed Services với `[FromKeyedServices]`

### Giới thiệu

ASP.NET Core hỗ trợ **keyed services** — cho phép đăng ký nhiều implementations của cùng một interface với keys khác nhau.

### Đăng ký Keyed Services

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

// Đăng ký nhiều implementations với keys khác nhau
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

builder.Services.AddControllers();
```

### Định nghĩa Interface và Implementations

```csharp
public interface ICache
{
    object Get(string key);
}

public class BigCache : ICache
{
    public object Get(string key) =>
        $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) =>
        $"Resolving {key} from small cache.";
}
```

### Sử dụng trong Controller

```csharp
[ApiController]
[Route("cache")]
public class CustomServicesApiController : Controller
{
    [HttpGet("big")]
    public ActionResult<object> GetBigCache(
        [FromKeyedServices("big")] ICache cache)
    {
        return cache.Get("data-mvc");
    }

    [HttpGet("small")]
    public ActionResult<object> GetSmallCache(
        [FromKeyedServices("small")] ICache cache)
    {
        return cache.Get("data-mvc");
    }
}
```

---

## Truy cập Settings với Options Pattern

### Pattern đề xuất

Truy cập app settings từ controller là pattern phổ biến. **Options Pattern** là cách tiếp cận được ưu tiên thay vì trực tiếp inject `IConfiguration`.

### Bước 1: Tạo Settings Class

```csharp
public class SampleWebSettings
{
    public string Title { get; set; }
    public int Updates { get; set; }
}
```

### Bước 2: Đăng ký Configuration

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IDateTime, SystemDateTime>();

    // Đăng ký settings với Options Pattern
    services.Configure<SampleWebSettings>(Configuration);

    services.AddControllersWithViews();
}
```

### Bước 3: Cấu hình đọc từ JSON file

```csharp
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("samplewebsettings.json",
                    optional: false,
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
```

### Bước 4: Sử dụng trong Controller

```csharp
public class SettingsController : Controller
{
    private readonly SampleWebSettings _settings;

    public SettingsController(
        IOptions<SampleWebSettings> settingsOptions)
    {
        _settings = settingsOptions.Value;
    }

    public IActionResult Index()
    {
        ViewData["Title"] = _settings.Title;
        ViewData["Updates"] = _settings.Updates;
        return View();
    }
}
```

---

## Controllers as Services

### Mặc định

Theo mặc định, ASP.NET Core **không đăng ký** controllers như services trong DI container. Runtime dùng `DefaultControllerActivator` để tạo controller instances và resolve services từ DI container cho constructor parameters.

### Kích hoạt Controllers as Services

```csharp
builder.Services.AddControllersWithViews()
    .AddControllersAsServices();
```

### Lợi ích

| Lợi ích                         | Mô tả                                       |
| ------------------------------- | ------------------------------------------- |
| **Custom IControllerActivator** | Intercept việc tạo controller               |
| **Lifetime Management**         | Dùng bất kỳ DI lifetime nào cho controllers |
| **Multi-constructor**           | DI container chọn constructor phù hợp       |

> **Lưu ý:** Cấu hình `ApplicationPartManager` **trước** khi gọi `AddControllersAsServices`. Xem thêm: [Share controllers, views, Razor Pages với Application Parts](https://learn.microsoft.com/en-us/aspnet/core/extensibility/using-ApplicationParts).

---

## So sánh các cách Injection

```mermaid
flowchart TD
    A["DI trong Controllers"] --> B["Constructor Injection"]
    A --> C["Action Injection"]
    A --> D["Keyed Services"]
    A --> E["Options Pattern"]

    B --> B1["✅ Dùng cho services dùng chung"]
    C --> C1["✅ Dùng cho services riêng từng action"]
    D --> D1["✅ Nhiều implementations cùng interface"]
    E --> E1["✅ Truy cập app configuration"]
```

---

## Tài liệu tham khảo

- [Dependency Injection in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection)
- [Options Pattern in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/options)
- [Test Controller Logic](https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/testing)
- [Keyed Service DI Support](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#keyed-services)
