---
title: Dependency Injection (Views)
description: Hướng dẫn chi tiết về Dependency Injection vào Views trong ASP.NET Core MVC — Configuration injection, Service injection, Populating Lookup Data và Overriding Services.
---

## Dependency Injection vào Views là gì?

ASP.NET Core hỗ trợ **dependency injection (DI)** vào views. Điều này hữu ích cho các view-specific services như **localization** hoặc **data chỉ dùng để populate view elements**.

```mermaid
flowchart TD
    A["🎨 View (.cshtml)"] --> B["@inject Directive"]
    B --> C["📦 DI Container"]
    C --> D["🛠️ Services"]
    D --> A
```

> **Lưu ý:** Hầu hết data mà views hiển thị nên được **truyền từ controller**. `@inject` chỉ nên dùng cho view-specific services.

---

## Configuration Injection

### Inject Configuration vào View

Giá trị từ settings files như `appsettings.json` và `appsettings.Development.json` có thể được inject vào view.

#### appsettings.Development.json

```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "MyRoot": {
    "MyParent": {
      "MyChildName": "Joe"
    }
  }
}
```

#### MVC View

```cshtml
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

@{
    ViewData["Title"] = "Privacy MVC";
}

<h1>@ViewData["Title"]</h1>

<p>MVC Use this page to detail your site's privacy policy.</p>

<h2>
    MyRoot:MyParent:MyChildName:
    @Configuration["MyRoot:MyParent:MyChildName"]
</h2>
```

---

## Service Injection với `@inject`

### Cú pháp

Sử dụng directive `@inject` để inject service vào view:

```cshtml
@using System.Threading.Tasks
@using ViewInjectSample.Model
@using ViewInjectSample.Model.Services

@model IEnumerable<ToDoItem>
@inject StatisticsService StatsService
```

### Ví dụ: ToDo List với Statistics

View này hiển thị danh sách `ToDoItem` cùng với statistics summary từ injected `StatisticsService`:

```cshtml
@using System.Threading.Tasks
@using ViewInjectSample.Model
@using ViewInjectSample.Model.Services

@model IEnumerable<ToDoItem>
@inject StatisticsService StatsService

<!DOCTYPE html>
<html>
<head>
    <title>To Do Items</title>
</head>
<body>
    <div>
        <h1>To Do Items</h1>

        <ul>
            <li>Total Items: @StatsService.GetCount()</li>
            <li>Completed: @StatsService.GetCompletedCount()</li>
            <li>Avg. Priority: @StatsService.GetAveragePriority()</li>
        </ul>

        <table>
            <tr>
                <th>Name</th>
                <th>Priority</th>
                <th>Is Done?</th>
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@item.Name</td>
                    <td>@item.Priority</td>
                    <td>@item.IsDone</td>
                </tr>
            }
        </table>
    </div>
</body>
</html>
```

### Đăng ký Service trong Program.cs

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

builder.Services.AddTransient<IToDoItemRepository, ToDoItemRepository>();
builder.Services.AddTransient<StatisticsService>();
builder.Services.AddTransient<ProfileOptionsService>();
```

### StatisticsService Implementation

```csharp
using System.Linq;
using ViewInjectSample.Interfaces;

namespace ViewInjectSample.Model.Services
{
    public class StatisticsService
    {
        private readonly IToDoItemRepository _toDoItemRepository;

        public StatisticsService(IToDoItemRepository toDoItemRepository)
        {
            _toDoItemRepository = toDoItemRepository;
        }

        public int GetCount() => _toDoItemRepository.List().Count();

        public int GetCompletedCount() =>
            _toDoItemRepository.List().Count(x => x.IsDone);

        public double GetAveragePriority()
        {
            var items = _toDoItemRepository.List();
            if (items.Count() == 0) return 0.0;
            return items.Average(x => x.Priority);
        }
    }
}
```

---

## Populating Lookup Data

### Vấn đề truyền thống

Rendering form với dropdown lists thường yêu cầu controller:

1. Request data access services cho mỗi tập options
2. Populate model hoặc ViewBag với các options

### Giải pháp: Inject Service vào View

```csharp
public class ProfileController : Controller
{
    public IActionResult Index()
    {
        // Chỉ cần truyền profile instance
        var profile = new Profile
        {
            Name = "Rick",
            FavColor = "Blue",
            Gender = "Male",
            State = new State("Ohio", "OH")
        };
        return View(profile);
    }
}
```

```cshtml
@using System.Threading.Tasks
@using ViewInjectSample.Model.Services

@model ViewInjectSample.Model.Profile
@inject ProfileOptionsService Options

<!DOCTYPE html>
<html>
<head>
    <title>Update Profile</title>
</head>
<body>
    <div>
        <h1>Update Profile</h1>

        Name: @Html.TextBoxFor(m => m.Name)
        <br />

        Gender: @Html.DropDownList("Gender",
            Options.ListGenders().Select(g =>
                new SelectListItem { Text = g, Value = g }))
        <br />

        State: @Html.DropDownListFor(m => m.State!.Code,
            Options.ListStates().Select(s =>
                new SelectListItem { Text = s.Name, Value = s.Code }))
        <br />

        Fav. Color: @Html.DropDownList("FavColor",
            Options.ListColors().Select(c =>
                new SelectListItem { Text = c, Value = c }))
    </div>
</body>
</html>
```

### ProfileOptionsService

```csharp
namespace ViewInjectSample.Model.Services
{
    public class ProfileOptionsService
    {
        public List<string> ListGenders()
        {
            return new List<string>() { "Female", "Male" };
        }

        public List<State> ListStates()
        {
            return new List<State>
            {
                new State("Alabama", "AL"),
                new State("Alaska", "AK"),
                new State("Ohio", "OH")
            };
        }

        public List<string> ListColors()
        {
            return new List<string>() { "Blue", "Green", "Red", "Yellow" };
        }
    }
}
```

> **Lưu ý:** Unregistered type sẽ throw exception tại runtime vì service provider được query nội bộ qua `GetRequiredService`.

---

## Overriding Services

### Default Fields có sẵn

View có sẵn các default fields:

| Field       | Mô tả           |
| ----------- | --------------- |
| `Html`      | HTML Helpers    |
| `Component` | View Components |
| `Url`       | URL Helpers     |

### Override Html Helper

Sử dụng `@inject` để override default HTML Helpers với phiên bản custom:

```cshtml
@using System.Threading.Tasks
@using ViewInjectSample.Helpers

@inject MyHtmlHelper Html

<!DOCTYPE html>
<html>
<head>
    <title>My Helper</title>
</head>
<body>
    <div>
        Test: @Html.Value
    </div>
</body>
</html>
```

---

## So sánh: Controller DI vs View DI

```mermaid
flowchart TD
    A["Dependency Injection"] --> B["Controller DI"]
    A --> C["View DI (@inject)"]
    B --> B1["✅ Controller nhận services"]
    B1 --> B2["Business logic"]
    C --> C1["✅ View nhận services"]
    C1 --> C2["Localiztion"]
    C1 --> C3["Lookup data"]
    C1 --> C4["Statistics"]
```

| Tiêu chí        | Controller DI               | View DI (@inject)      |
| --------------- | --------------------------- | ---------------------- |
| **Mục đích**    | Business logic, data access | View-specific services |
| **Cú pháp**     | Constructor injection       | `@inject` directive    |
| **Testability** | Cao                         | Thấp hơn               |
| **Khuyến nghị** | ✅ Ưu tiên dùng             | Hạn chế, chỉ khi cần   |

---

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

- [Dependency injection into controllers](https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection)
- [Configuration in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration)
- [Views in ASP.NET Core MVC](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/overview)
- [Getting Lookup Data Into Your View](https://blog.simontimms.com/2015/06/09/getting-lookup-data-into-you-view/)
