---
title: Partial Views
description: Giới thiệu chi tiết về Partial Views trong ASP.NET Core MVC — cách khai báo, tham chiếu và truyền dữ liệu.
---

## Partial View là gì?

**Partial view** là một Razor markup file (`.cshtml`) **không có directive `@page`**, dùng để render HTML output bên trong output của một markup file khác.

Trong MVC, markup files được gọi là **views**; trong Razor Pages, chúng được gọi là **pages**. Thuật ngữ "partial view" dùng chung cho cả hai.

---

## Khi nào nên dùng Partial Views

Partial views hiệu quả trong các trường hợp:

| Trường hợp                | Mô tả                                                                                                                                               |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Chia nhỏ file lớn**     | Trong một markup file phức tạp gồm nhiều phần logic, có lợi khi làm việc với từng phần tách biệt trong partial view                                 |
| **Giảm trùng lặp markup** | Khi cùng markup được dùng ở nhiều file, partial view loại bỏ sự trùng lặp — thay đổi một lần trong partial view sẽ cập nhật tất cả các file dùng nó |

### Không nên dùng Partial Views khi

- **Duy trì layout chung** → Dùng `_Layout.cshtml`
- **Cần logic phức tạp hoặc code execution để render** → Dùng **View Component**

---

## Khai báo Partial View

Một partial view là file `.cshtml` **không có `@page` directive**, nằm trong thư mục `Views` (MVC) hoặc `Pages` (Razor Pages).

### Quy ước đặt tên

Tên file partial view thường bắt đầu bằng **dấu gạch dưới `_`**. Quy ước này không bắt buộc nhưng giúp phân biệt trực quan partial views với views và pages.

```
MyApp/
├── Views/
│   ├── Home/
│   │   ├── Index.cshtml
│   │   ├── About.cshtml
│   │   └── _Header.cshtml      ← Partial view
│   ├── Products/
│   │   ├── Index.cshtml
│   │   └── _ProductCard.cshtml  ← Partial view
│   └── Shared/
│       ├── _Footer.cshtml       ← Partial view dùng chung
│       └── _AuthorBio.cshtml   ← Partial view dùng chung
```

> **Lưu ý:** Không giống MVC view rendering, partial view **không chạy `_ViewStart.cshtml`**.

---

## Tham chiếu Partial View

Có nhiều cách để tham chiếu partial view trong markup file. **Khuyến nghị** dùng cách async.

### 1. Partial Tag Helper (Khuyến nghị)

**Partial Tag Helper** render content **asynchronously** và sử dụng syntax giống HTML. Yêu cầu **ASP.NET Core 2.1+**.

```cshtml
@* Cú pháp cơ bản — không cần extension *@
<partial name="_PartialName" />
```

```cshtml
@* Khi có extension, partial phải cùng folder với file gọi *@
<partial name="_PartialName.cshtml" />
```

#### Tham chiếu từ app root

```cshtml
@* Razor Pages *@
<partial name="~/Pages/Folder/_PartialName.cshtml" />
<partial name="/Pages/Folder/_PartialName.cshtml" />

@* MVC *@
<partial name="~/Views/Folder/_PartialName.cshtml" />
<partial name="/Views/Folder/_PartialName.cshtml" />
```

#### Tham chiếu bằng relative path

```cshtml
<partial name="../Account/_PartialName.cshtml" />
```

---

### 2. HTML Helper — Async (Khuyến nghị)

Dùng `PartialAsync` trả về `IHtmlContent` wrapped trong `Task`. Phải prefix với `@`:

```cshtml
@await Html.PartialAsync("_PartialName")
```

```cshtml
@await Html.PartialAsync("_PartialName.cshtml")
```

#### Tham chiếu từ app root

```cshtml
@await Html.PartialAsync("~/Views/Folder/_PartialName.cshtml")
@await Html.PartialAsync("/Views/Folder/_PartialName.cshtml")
```

#### Tham chiếu bằng relative path

```cshtml
@await Html.PartialAsync("../Account/_LoginPartial.cshtml")
```

---

### 3. HTML Helper — Render Async

`RenderPartialAsync` **streams** rendered output trực tiếp đến response, không trả về `IHtmlContent`. Phải gọi trong Razor code block:

```cshtml
@{
    await Html.RenderPartialAsync("_AuthorPartial");
}
```

> `RenderPartialAsync` có **hiệu năng tốt hơn** trong một số scenario vì không buffer kết quả. Benchmark để chọn cách phù hợp.

---

### 4. HTML Helper — Sync (Không khuyến nghị)

`Partial` và `RenderPartial` là phiên bản synchronous. **Không khuyến nghị** vì có thể gây deadlock.

> **Cảnh báo:** Visual Studio sẽ cảnh báo khi dùng `Partial`:
> _"Use of IHtmlHelper.Partial may result in application deadlocks. Consider using `<partial>` Tag Helper or IHtmlHelper.PartialAsync."_

---

## Partial View Discovery

Khi partial view được tham chiếu **mà không có extension**, thứ tự tìm kiếm như sau:

### MVC

```mermaid
flowchart TD
    A["Tham chiếu: _PartialName"] --> B1["1️⃣ /Areas/{Area}/Views/{Controller}/"]
    B1 -->|Không tìm thấy| B2["2️⃣ /Areas/{Area}/Views/Shared/"]
    B2 -->|Không tìm thấy| B3["3️⃣ /Views/Shared/"]
    B3 -->|Không tìm thấy| B4["4️⃣ /Pages/Shared/"]
    B4 -->|Không tìm thấy| C["❌ Lỗi: Partial not found"]
```

### Quy ước quan trọng

- Partial views **cùng tên** nhưng **khác folder** → được phép
- Khi tìm **không có extension**: nếu partial view tồn tại ở **cả caller folder và Shared folder** → partial ở **caller folder** được ưu tiên
- Partial views có thể **chuỗi** (partial gọi partial khác), miễn không tạo **circular reference**
- **Relative paths** luôn relative với **current file**, không phải root

> **Lưu ý:** Razor section định nghĩa trong partial view **không thấy** được bởi parent markup file. Section chỉ visible trong partial view nó được định nghĩa.

---

## Truyền dữ liệu đến Partial Views

### ViewData

Khi partial view được khởi tạo, nó nhận **bản sao** của `ViewData` dictionary từ parent. Thay đổi trong partial view **không ảnh hưởng** parent view.

```cshtml
@await Html.PartialAsync("_PartialName", customViewData)
```

```cshtml
@* Với Partial Tag Helper *@
<partial name="_PartialName" view-data="customViewData" />
```

---

### Truyền Model

Model có thể là bất kỳ object nào:

```cshtml
@* PartialAsync — async, trả về IHtmlContent *@
@await Html.PartialAsync("_ProductCard", product)

@* RenderPartialAsync — async, stream trực tiếp *@
@{ await Html.RenderPartialAsync("_ProductCard", product); }
```

---

### Ví dụ: Article với Sections

#### View chính

```cshtml
@model Article

<h2>@Model.Title</h2>

@* Partial view đơn giản — truyền string *@
@await Html.PartialAsync("_AuthorPartial", Model.AuthorName)

@Model.PublicationDate

@* Loop truyền model + ViewData *@
@{
    var index = 0;
    foreach (var section in Model.Sections)
    {
        @(await Html.PartialAsync("_ArticleSection",
                                section,
                                new ViewDataDictionary(ViewData)
                                {
                                    { "index", index }
                                }))
        index++;
    }
}
```

#### Partial 1: `_AuthorPartial.cshtml`

```cshtml
@model string

<div>
    <h3>@Model</h3>
    Tác giả từ /Views/Shared/_AuthorPartial.cshtml.
</div>
```

#### Partial 2: `_ArticleSection.cshtml`

```cshtml
@using MyApp.ViewModels
@model ArticleSection

<h3>@Model.Title — Index: @ViewData["index"]</h3>
<div>
    @Model.Content
</div>
```

---

## So sánh các cách render Partial View

| Cách                   | Async    | Trả về         | Performance  | Khuyến nghị              |
| ---------------------- | -------- | -------------- | ------------ | ------------------------ |
| `<partial>` Tag Helper | ✅ Async | `IHtmlContent` | Tốt          | ✅ **Ưu tiên**           |
| `PartialAsync`         | ✅ Async | `IHtmlContent` | Tốt          | ✅ Khuyến nghị           |
| `RenderPartialAsync`   | ✅ Async | Stream         | **Tốt nhất** | Dùng khi cần performance |
| `Partial`              | ❌ Sync  | `IHtmlContent` | Trung bình   | ❌ Tránh dùng            |
| `RenderPartial`        | ❌ Sync  | Stream         | Tốt          | ❌ Tránh dùng            |

---

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

- [Razor Syntax Reference](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor)
- [Tag Helpers](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)
- [Partial Tag Helper](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/partial)
- [View Components](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components)
- [Areas](https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/areas)
