Nguon: Microsoft Learn · .NET 8.0

Partial Views (View cục bộ) trong ASP.NET Core

Nguồn: Partial views in ASP.NET Core

Bởi Steve Smith, Maher JENDOUBI, Rick Anderson, và Scott Sauber

Một partial view (view cục bộ) là một file markup Razor (.cshtml) không có chỉ thị @page, dùng để render (kết xuất) đầu ra HTML bên trong đầu ra đã render của một file markup khác.

Thuật ngữ partial view được sử dụng khi phát triển ứng dụng MVC (trong đó file markup gọi là views) hoặc ứng dụng Razor Pages (trong đó file markup gọi là pages). Bài viết này dùng chung thuật ngữ markup files cho cả views và pages.

Xem hoặc tải xuống mã mẫu

Khi nào nên dùng partial views

Partial views là cách hiệu quả để:

Trong một file markup lớn và phức tạp gồm nhiều phần logic, việc làm việc với từng phần được tách biệt vào một partial view có nhiều lợi thế. Code trong file markup sẽ dễ quản lý hơn vì markup chỉ chứa cấu trúc trang tổng thể và các tham chiếu đến partial views.

Khi các phần tử markup giống nhau được sử dụng trong nhiều file markup, một partial view loại bỏ sự trùng lặp đó vào một file partial view duy nhất. Khi markup trong partial view được thay đổi, nó cập nhật đầu ra render của tất cả các file markup sử dụng partial view đó.

Partial views không nên dùng để duy trì các phần tử layout (bố cục) chung. Các phần tử layout chung nên được chỉ định trong các file _Layout.cshtml.

Không nên dùng partial view khi cần logic render phức tạp hoặc thực thi code. Thay vào đó, hãy dùng view component.

Khai báo partial views

Một partial view là file markup .cshtml không có chỉ thị @page, được đặt trong thư mục Views (MVC) hoặc Pages (Razor Pages).

Trong ASP.NET Core MVC, ViewResult của controller có thể trả về một view hoặc một partial view. Trong Razor Pages, một PageModel có thể trả về partial view dưới dạng đối tượng PartialViewResult.

Khác với việc render view/page trong MVC, partial view không chạy _ViewStart.cshtml. Xem thêm về _ViewStart.cshtml trong bài Layout in ASP.NET Core.

Tên file partial view thường bắt đầu bằng dấu gạch dưới (_). Quy ước đặt tên 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.

Tham chiếu partial view

Dùng partial view trong Razor Pages PageModel

Từ ASP.NET Core 2.2 trở lên, handler method có thể gọi phương thức Partial để trả về đối tượng PartialViewResult:

csharp
public IActionResult OnGetPartial() =>
    Partial("_AuthorPartialRP");

Dùng partial view trong file markup

Có nhiều cách tham chiếu partial view trong file markup. Nên dùng một trong các cách render bất đồng bộ sau:

Partial Tag Helper

Partial Tag Helper yêu cầu ASP.NET Core 2.1 trở lên.

Partial Tag Helper render nội dung bất đồng bộ và sử dụng cú pháp giống HTML:

cshtml
<partial name="_PartialName" />

Khi có phần mở rộng file, Tag Helper tham chiếu partial view phải cùng thư mục với file markup đang gọi:

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

Ví dụ tham chiếu partial view từ gốc ứng dụng. Đường dẫn bắt đầu bằng ~/ hoặc / trỏ về gốc ứng dụng:

Razor Pages

cshtml
<partial name="~/Pages/Folder/_PartialName.cshtml" />
<partial name="/Pages/Folder/_PartialName.cshtml" />

MVC

cshtml
<partial name="~/Views/Folder/_PartialName.cshtml" />
<partial name="/Views/Folder/_PartialName.cshtml" />

Ví dụ tham chiếu partial view bằng đường dẫn tương đối:

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

Asynchronous HTML Helper (HTML Helper bất đồng bộ)

Khi dùng HTML Helper, cách tốt nhất là dùng PartialAsync. PartialAsync trả về kiểu IHtmlContent được bọc trong Task<TResult>. Phương thức được tham chiếu bằng cách thêm ký tự @ trước lời gọi await:

cshtml
@await Html.PartialAsync("_PartialName")

Khi có phần mở rộng file:

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

Tham chiếu từ gốc ứng dụng:

Razor Pages

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

MVC

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

Tham chiếu bằng đường dẫn tương đối:

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

Ngoài ra, có thể render partial view bằng RenderPartialAsync. Phương thức này không trả về IHtmlContent mà stream (phát) đầu ra render trực tiếp vào response. Vì không trả về kết quả, phải gọi nó trong khối code Razor:

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

RenderPartialAsync stream nội dung render nên cung cấp hiệu suất tốt hơn trong một số kịch bản.

Synchronous HTML Helper (HTML Helper đồng bộ)

PartialRenderPartial là các tương đương đồng bộ của PartialAsyncRenderPartialAsync. Không khuyến nghị dùng các phương thức đồng bộ vì có những kịch bản chúng gây deadlock (khóa chết). Các phương thức đồng bộ dự kiến sẽ bị loại bỏ trong phiên bản tương lai.

Quan trọng: Nếu cần thực thi code, hãy dùng view component thay vì partial view.

Gọi Partial hoặc RenderPartial sẽ sinh ra cảnh báo từ Visual Studio analyzer:

Sử dụng IHtmlHelper.Partial có thể gây deadlock trong ứng dụng. Hãy cân nhắc dùng <partial> Tag Helper hoặc IHtmlHelper.PartialAsync.

Thay thế các lời gọi @Html.Partial bằng @await Html.PartialAsync hoặc Partial Tag Helper.

Partial view discovery (Tìm kiếm partial view)

Khi tham chiếu partial view bằng tên mà không có phần mở rộng file, các vị trí sau được tìm kiếm theo thứ tự:

Razor Pages

  1. Thư mục của page đang thực thi
  2. Cấu trúc thư mục phía trên thư mục của page
  3. /Shared
  4. /Pages/Shared
  5. /Views/Shared

MVC

  1. /Areas/<Area-Name>/Views/<Controller-Name>
  2. /Areas/<Area-Name>/Views/Shared
  3. /Views/Shared
  4. /Pages/Shared

Các quy tắc sau áp dụng cho việc tìm kiếm partial view:

Lưu ý: section được định nghĩa trong partial view không hiển thị trong các file markup cha. section chỉ hiển thị trong partial view nơi nó được định nghĩa.

Truy cập dữ liệu từ partial views

Khi partial view được khởi tạo, nó nhận một bản sao của dictionary ViewData từ parent (cha). Các cập nhật dữ liệu trong partial view không được lưu vào view cha. Các thay đổi ViewData trong partial view bị mất khi partial view kết thúc.

Ví dụ truyền instance ViewDataDictionary vào partial view:

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

Có thể truyền model vào partial view:

cshtml
@await Html.PartialAsync("_PartialName", model)

Razor Pages - Ví dụ từ trang Pages/ArticlesRP/ReadRP.cshtml:

cshtml
@model ReadRPModel

<h2>@Model.Article.Title</h2>
@* Truyền tên tác giả vào Pages\Shared\_AuthorPartialRP.cshtml *@
@await Html.PartialAsync("../Shared/_AuthorPartialRP", Model.Article.AuthorName)
@Model.Article.PublicationDate

@* Lặp qua các Sections và truyền vào section cùng ViewData bổ sung *@
@{
    var index = 0;

    foreach (var section in Model.Article.Sections)
    {
        await Html.PartialAsync("_ArticleSectionRP", 
                                section,
                                new ViewDataDictionary(ViewData)
                                {
                                    { "index", index }
                                });

        index++;
    }
}

Pages/Shared/_AuthorPartialRP.cshtml:

cshtml
@model string
<div>
    <h3>@Model</h3>
    This partial view from /Pages/Shared/_AuthorPartialRP.cshtml.
</div>

Pages/ArticlesRP/_ArticleSectionRP.cshtml:

cshtml
@using PartialViewsSample.ViewModels
@model ArticleSection

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

MVC - Ví dụ từ view Views/Articles/Read.cshtml:

cshtml
@model PartialViewsSample.ViewModels.Article

<h2>@Model.Title</h2>
@* Truyền tên tác giả vào Views\Shared\_AuthorPartial.cshtml *@
@await Html.PartialAsync("_AuthorPartial", Model.AuthorName)
@Model.PublicationDate

@{
    var index = 0;

    foreach (var section in Model.Sections)
    {
        @(await Html.PartialAsync("_ArticleSection", 
                                section,
                                new ViewDataDictionary(ViewData)
                                {
                                    { "index", index }
                                }))

        index++;
    }
}

Views/Shared/_AuthorPartial.cshtml:

cshtml
@model string
<div>
    <h3>@Model</h3>
    This partial view from /Views/Shared/_AuthorPartial.cshtml.
</div>

Views/Articles/_ArticleSection.cshtml:

cshtml
@using PartialViewsSample.ViewModels
@model ArticleSection

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

Khi chạy, các partial views được render vào đầu ra của file markup cha, và file này được render trong _Layout.cshtml chia sẻ.