View trong ASP.NET Core

MVC (Model - View - Controller) là mẫu thiết kế được sử dụng trên nhiều công nghệ khác nhau, từ Smalltalk đến C++, Java và bây giờ là C# và .NET.

  • Mẫu thiết kế MVC là mẫu thiết kế phổ biến cho tầng giao diện người dùng của ứng dụng phần mềm.
  • Trong các ứng dụng lớn, bạn thường kết hợp mẫu thiết kế MVC của tầng UI với các mẫu thiết kế khác trong ứng dụng, như các mẫu truy cập dữ liệu và các mẫu IoC, mẫu DI, ...
  • Tất cả sẽ kết hợp cùng nhau để xây dựng nên ứng dụng hoàn chỉnh.

MVC tách giao diện người dùng (UI) của một ứng dụng thành ba phần sau:

  • Model: Một tập hợp các lớp mô tả dữ liệu bạn đang làm việc.
  • View: Định nghĩa giao diện người dùng.
  • Controller: Một tập hợp các lớp xử lý giao tiếp từ người dùng, luồng ứng dụng tổng thể và logic dành riêng cho ứng dụng.
Kiến trúc MVC

Ở hướng dẫn này, chúng ta sẽ cùng tìm hiểu về View trong ASP.NET Core.

View là gì?

Trong mẫu Model-View-Controller (MVC), View đóng vai trò trình bày giao diện người dùng của ứng dụng. View là các mẫu HTML sử dụng cú pháp Razor để tạo nội dung trả về cho client.

View trong ASP.NET Core MVC là các file có phần mở rộng là .cshtml được lưu mặc định tại thư mục Views trong ứng dụng.

Thông thường, mỗi controller sẽ có thư mục riêng, thư mục này nằm trong thư mục Views và có tên trùng với tên của controller, trong đó là các View cho các hành động của controller cụ thể.

Thư mục Views trong Solution Explorer

Ngoài View cho các action còn có các view đặc biệt như partial view, view layout, view start, view imports được sử dụng để giảm sự lặp lại và cho phép tái sử dụng trong các view của ứng dụng.

Xem thêm về view layout, view start và view imports trong ASP.NET Core tại đây:

View Layout, View Start, View Imports trong ASP.NET Core
View Layout, View Start, View Imports là gì? Lợi ích và các sử dụng View Layout, View Start, View Imports trong ASP.NET Core.

Lợi ích của View

View cung cấp sự phân tách các mối quan tâm trong một ứng dụng MVC, nó đóng gói giao diện người dùng tách biệt với các logic nghiệp vụ.

View trong ASP.NET MVC sử dụng cú pháp Razor giúp dễ dàng nhúng các biểu thức C# sẽ được xử lý ở phía máy chủ vào mã HTML.

Các thành phần phổ biến, lặp đi lặp lại của giao diện người dùng ứng dụng có thể dễ dàng được tái sử dụng giữa các view bằng cách sử dụng view layout và partial view.

Tạo View trong ASP.NET Core

View dành cho các hành động (action) của controller được tạo trong thư mục /Views/[controller name]. Những view được chia sẻ giữa các controller được đặt trong thư mục /Views/Shared. Tên của View phải giống như tên của hành động của controller và có phần mở rộng là .cshtml.

Ví dụ: để tạo view cho hành động About của HomeController, bạn sẽ tạo file About.cshtml trong thư mục /Views/Home:

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>Use this area to provide additional information.</p>

Mã Razor được bắt đầu bằng ký hiệu @. Các câu lệnh C# được chạy trong các khối mã Razor được đặt trong cặp dấu ngoặc nhọn {}, chẳng hạn như gán giá trị "About" cho phần tử ViewData["Title"] trong ví dụ trên.

Razor có thể được sử dụng để hiển thị các giá trị trong HTML bằng cách tham chiếu giá trị bằng ký hiệu @, như được hiển thị bên trong các phần tử <h2><h3> ở trên.

View chỉ tập trung vào phần HTML đầu ra mà nó chịu trách nhiệm. Những thành phần còn lại của một trang HTML sẽ được xử lý trong view layout.

Làm thế nào để controller chỉ định view?

View thường được trả về từ các phương thức hành động như một ViewResult. Phương thức hành động của bạn có thể khởi tạo và trực tiếp trả về ViewResult, nhưng phổ biến hơn nếu controller của bạn kế thừa từ lớp Controller, bạn sẽ chỉ cần sử dụng phương thức trợ giúp View để trả về ViewResult.

Ví dụ sau minh họa về phương thức hành động About của HomeController.cs:

public IActionResult About()
{
	ViewData["Message"] = "Your application description page.";

	return View();
}

Phương thức trợ giúp View có một số quá tải để trả về View dễ dàng hơn cho các nhà phát triển ứng dụng. Bạn có thể tùy ý chỉ định một View để trả về, cũng như một đối tượng model để chuyển đến cho View.

Khi chạy ứng dụng và truy cập đường dẫn /Home/About, view About.cshtml ở trên được hiển thị như sau:

View About.cshtml hiển thị trong trang About

Tìm kiếm View trong ASP.NET Core

Khi một phương thức hành động trả về view, một quá trình được gọi là tìm kiếm View sẽ diễn ra. Quá trình này xác định view nào sẽ được sử dụng. Bộ thực thi sẽ tìm view trong thư mục /Views/[controller name] trước, nếu không có nó sẽ tiếp tục tìm view trong thư mục /Views/Shared.

Khi một hành động trả về phương thức View(), nếu bạn không truyền tên view vào phương thức View() thì tên của hành động được sử dụng làm tên view. Ví dụ: phương thức hành động có tên là Index, thì view sẽ có tên là Index. Tên view cũng có thể được chỉ định rõ ràng cho phương thức View(), ví dụ: return View("SomeView");. Trong cả hai trường hợp này, bộ thực thi sẽ tìm kiếm view phù hợp trong:

  1. Views/<ControllerName>/<ViewName>.cshtml
  2. Views/Shared/<ViewName>.cshtml
Tip: Chúng tôi khuyên bạn nên tuân theo quy ước đơn giản là trả về View() từ các phương thức hành động khi có thể. Vì nó giúp mã linh hoạt hơn và dễ dàng hơn khi tái cấu trúc lại mã.

Bạn cũng có thể cung cấp một đường dẫn đến file view thay vì chỉ cung cấp tên view. Trong trường hợp này, phần mở rộng .cshtml phải được chỉ định làm một phần của đường dẫn tới file view. Đường dẫn phải liên quan đến thư mục gốc của ứng dụng (và có thể tùy chọn bắt đầu bằng ký tự "/" hoặc "~/"). Ví dụ: return View("Views/Home/About.cshtml");

Tip: Tên view có thể phân biệt chữ hoa chữ thường tùy thuộc vào hệ điều hành. Để tương thích giữa các hệ điều hành, bạn phải đặt tên các thư mục, tên file view trùng khớp với tên controller, tên phương thức hành động.

Truyền dữ liệu cho View

Bạn có thể truyền dữ liệu cho view bằng nhiều cơ chế. Cách tiếp cận mạnh mẽ nhất là chỉ định một kiểu model cho view, sau đó truyền một thể hiện của kiểu này sang view từ phương thức hành động.

Chúng tôi khuyên bạn nên sử dụng model để truyền dữ liệu đến view. Điều này cho phép view tận dụng lợi thế của việc kiểm tra định kiểu mạnh. Bạn có thể chỉ định một kiểu model cho view bằng cách sử dụng @model như sau:

@model WebApplication1.ViewModels.Address
<h2>Contact</h2>
<address>
    @Model.Street<br />
    @Model.City, @Model.State @Model.PostalCode<br />
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

Khi model đã được chỉ định cho view, thể hiện của model được gửi đến view có thể được truy cập bằng cách sử dụng @Model như được trình bày ở trên. Để cung cấp một thể hiện của model cho view, controller sẽ truyền nó dưới dạng tham số như sau:

public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    var viewModel = new Address()
    {
        Name = "Microsoft",
        Street = "One Microsoft Way",
        City = "Redmond",
        State = "WA",
        PostalCode = "98052-6399"
    };
    return View(viewModel);
}

Không có hạn chế về các kiểu dữ liệu của model có thể được cung cấp cho view. Chúng tôi khuyên bạn nên sử dụng các model chỉ có các thuộc tính và không có phương thức. Một ví dụ về cách tiếp cận này là model Address được sử dụng trong ví dụ trên:

namespace WebApplication1.ViewModels
{
    public class Address
    {
        public string Name { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
    }
}
Lưu ý: Không có gì ngăn cản bạn sử dụng các lớp model với đầy đủ phương thức xử lý logic nghiệp vụ. Tuy nhiên, việc tách biệt logic nghiệp vụ và model giúp mã của bạn dễ đọc, dễ bảo trì và cũng có thể cung cấp một số lợi ích bảo mật.

Kiểu dữ liệu lỏng lẻo

Ngoài những view được định kiểu mạnh, tất cả các view đều có thể truy cập vào danh sách dữ liệu được định kiểu lỏng lẻo. Danh sách này có thể được truy cập thông qua một trong hai thuộc tính ViewData hoặc ViewBag trên controller và view. Trong đó thuộc tính ViewBag đã bao hàm luôn thuộc tính ViewData.

ViewData là một đối tượng từ điển được truy cập thông qua các khóa string. Bạn có thể lưu trữ và truy xuất các đối tượng trong đó và bạn sẽ cần phải ép kiểu mỗi khi truy xuất. Bạn có thể sử dụng ViewData để truyền dữ liệu từ controller sang view, và giữa các view với nhau (view và layout). Dữ liệu kiểu string có thể được lưu trữ và sử dụng trực tiếp mà không cần phải ép kiểu.

Ví dụ dưới đây sẽ gán một số giá trị cho ViewData trong phương thức hành động:

public IActionResult SomeAction()
{
    ViewData["Greeting"] = "Hello";
    ViewData["Address"]  = new Address()
    {
        Name = "Steve",
        Street = "123 Main St",
        City = "Hudson",
        State = "OH",
        PostalCode = "44236"
    };

    return View();
}

Làm việc với dữ liệu trong view:

@{
    // Requires cast
    var address = ViewData["Address"] as Address;
}

@ViewData["Greeting"] World!

<address>
    @address.Name<br />
    @address.Street<br />
    @address.City, @address.State @address.PostalCode
</address>

Đối tượng ViewBag bao hàm luôn ViewData nên nó cung cấp truy cập động đến các đối tượng được lưu trữ trong ViewData. Điều này rất tiện lợi vì nó không yêu cầu phải ép kiểu trước khi sử dụng. Sử dụng ViewBag cho ví dụ trên:

@ViewBag.Greeting World!

<address>
    @ViewBag.Address.Name<br />
    @ViewBag.Address.Street<br />
    @ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode
</address>

View động

Những view không khai báo một kiểu model nhưng có một thể hiện của model được truyền cho chúng thì chúng cũng có thể truy cập đối tượng này.

Ví dụ: nếu một thể hiện của Address được truyền đến một view không khai báo @model, thì view vẫn có thể truy cập các thuộc tính của thể hiện như sau:

<address>
    @Model.Street<br />
    @Model.City, @Model.State @Model.PostalCode<br />
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

Tính năng này khá linh hoạt, nhưng nó không cung cấp bất kỳ bảo vệ khi biên dịch hoặc IntelliSense nào. Nếu thuộc tính không tồn tại, trang sẽ bị lỗi khi chạy.

Kết luận

Bài viết này đã trình bày về View trong ASP.NET Core, từ khái niệm View trong mô hình MVC đến cách tạo view, truyền model tới view, ViewBag, ViewData, ...

Nếu có bất kỳ câu hỏi gì, bạn đừng ngần ngại để lại comment ở phía dưới nhé. Mình sẽ cố gắng phản hồi sớm trong vòng 24 giờ.

Ở hướng dẫn tiếp theo mình sẽ trình bày về partial view, dependency injection trong view.



Bài viết liên quan:

View Layout, View Start, View Imports là gì? Lợi ích và các sử dụng View Layout, View Start, View Imports trong ASP.NET Core.

ActionResult trong ASP.NET Core là gì? Có những loại ActionResult nào? Làm sao để sử dụng ActionResult trong ASP.NET Core.

Routing trong ASP.NET Core là gì? Làm sao để cấu hình định tuyến trong ASP.NET Core.