ASP.NET MVC Core 的控制器可以利用視圖返回格式化結果。 ...
原文:Views Overview
作者:Steve Smith
翻譯:姚阿勇(Dr.Yao)
校對:高嵩(Jack)
ASP.NET MVC Core 的控制器可以利用 視圖 返回格式化結果。
什麼是視圖?
在模型-視圖-控制器(MVC)模式中,視圖 封裝用戶與應用交互的表現細節。視圖是帶有嵌入代碼的 HTML 模版,用以生成發送給客戶端的內容。視圖採用 Razor 語法,該語法允許以最小的代碼量或複雜度與 HTML 進行編碼交互。
ASP.NET Core MVC 視圖預設以 .cshtml 文件保存在應用程式的 Views 文件夾裡面。通常,每個控制器都會有自己的文件夾,裡面是對應控制器操作的視圖。
除了對應操作的視圖,局部視圖,佈局,以及其他特定視圖文件可以用來幫助減少重覆並允許在應用視圖裡重用。
使用視圖的好處
視圖在 MVC 應用中提供關註點分離,將用戶界面層級的標記從業務邏輯中封裝出來。ASP.NET MVC 視圖採用Razor 語法在 HTML 標記和服務端邏輯之間進行輕鬆切換。通常,可以通過佈局與共用指令或者局部視圖對應用的用戶界面中重覆的外觀輕鬆地進行復用。
創建視圖
屬於某個控制器的視圖創建在 Views/[ControllerName] 文件夾下。在控制器之間共用的視圖則放在 /Views/Shared 文件夾下。將視圖文件命名為與其關聯的控制器操作一樣的名字,並添加 .cshtml 文件擴展名。例如,為 Home 控制器的 About 操作創建一個視圖,你應該在 /Views/Home 文件夾下創建一個 About.cshtml 文件。
一個示例視圖文件 ( About.cshtml ):
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<p>Use this area to provide additional information.</p>
@
符號代表 Razor 代碼。 C# 語句在大括弧( {
}
)包裹的 Razor 代碼塊中運行,就像上面展示的用 “About” 給 ViewData["Title"]
元素進行的賦值操作那樣。Razor 可以通過簡單地用 @
符號對值進行引用從而在 HTML 里顯示它們,就像上面 <h2>
和 <h3>
元素裡面展示的那樣。
這個視圖只關心由它負責的這部分輸出。而頁面佈局的其餘部分,以及視圖中的通用外觀,則在別的地方指定。瞭解更多關於佈局與共用視圖邏輯。
控制器如何指定視圖?
視圖通常作為一個ViewResult從操作中返回。你的操作方法可以直接返回一個 ViewResult
,但是更常見的是如果你的控制器是繼承自Controller的,那麼可以簡單地使用 View
輔助方法,如下例所示:
HomeController.cs
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View(); //手動高亮
}
這個 View
輔助方法有多個重載版本以便於幫助應用開發人員返回視圖。你可以有選擇性地指定一個返回的視圖,還可以給視圖傳遞一個模型對象。
當這個操作返回時,上面展示的 About.cshtml 視圖將會被渲染:
視圖發現
當操作返回視圖的時,會進行一個叫做 視圖發現 的過程。這個過程決定哪個視圖文件將被採用。如果沒有指定特定的視圖文件,運行時首先會尋找與控制器對應的視圖,然後再去 Shared 文件夾里尋找匹配的視圖名稱。
當操作返回 View
方法,就像 return View();
這樣,這個操作的名字則被用作視圖名稱。例如,假如這是從一個叫做 “ Index ” 的操作方法調用的,那麼它就等價於傳遞了一個視圖名稱 “ Index ” 。也可以給這個方法傳遞一個明確的視圖名稱( return View("SomeView");
)。在這兩種情況中,視圖探尋都會在以下位置搜索匹配的視圖文件:
- Views/<控制器名稱>/<視圖名稱>.cshtml
- Views/Shared/<視圖名稱>.cshtml
我們推薦遵循約定,在可能的情況下簡單地從操作中返回
View()
,這樣會更加靈活,更易於重構代碼。
可以提供視圖文件路徑,而非視圖名。在這種情況下,.cshtml 擴展名必須作為文件路徑的一部分明確指定。路徑可以是相對於應用程式根目錄的(可以選擇性地以 “ / ” 或者 “ ~/ ” 開頭)。例如: return View("Views/Home/About.cshtml");
你可以通過自定義的IViewLocationExpander來定製關於應用中的視圖位於哪裡的預設約定。
取決於基本文件系統,視圖名稱可能會區分大小寫。為了跨系統的相容性,應當總是保持控制器與操作名稱同相關聯的視圖文件夾與文件名之間保持大小寫一致。
給視圖傳遞數據
你可以使用多種機制給視圖傳遞數據。最健壯的方式就是在視圖中指定一個 模型 類型(通常稱為 視圖模型 ,以區別於業務領域的模型類型 ),然後從操作中給視圖傳遞一個該類型的實例。我們推薦你採用模型或視圖模型給視圖傳遞數據。這使得視圖可以利用到強類型檢查的優勢。你可以通過 @model
指令為視圖指定一個模型:
@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>
一旦為視圖指定了模型,就可以像上面展示的那樣,通過 @Model
以強類型的方式訪問發送給視圖的實例。為了給視圖提供模型類型的實例,控制器將其作為參數傳遞進去:
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); // 手動高亮
}
對於能夠作為模型提供給視圖的類型沒有限制。我們推薦傳遞具有少量行為或者沒有行為的普通舊 CLR 對象(Plain Old CLR Object,POCO)視圖模型,這樣就可以在應用的其他地方封裝業務邏輯。這種方法的一個例子就是上面示例中的 Address 視圖模型:
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; }
}
}
雖然你可以使用相同的類作為你的業務模型類型和顯示模型類型。然而,將它們與你的領域或持久模型區分開來可以使視圖獨立地變化,並且還可以提供一些安全上的收益(對於那些用戶通過 模型綁定發送給應用的模型)。
弱類型數據
除了強類型視圖之外,所有的視圖都可以訪問弱類型的數據集合。這個集合可以通過控制器和視圖的 ViewData
或者 ViewBag
屬性來引用。ViewBag
屬性是對 ViewData
的封裝用以在集合上提供動態視圖。它不是一個獨立的集合。
ViewData
是一個通過 string
鍵訪問的字典對象。你可以在裡面儲存和查詢對象,並且在提取它們的時候無需轉換成特定的類型。可以利用 ViewData
從控制器傳遞數據給視圖,以及在視圖之間(還有局部視圖與佈局)。字元串數據可以直接儲存和使用,無需進行轉換。
在操作中為 ViewData
設置一些值:
public IActionResult SomeAction()
{
ViewData["Greeting"] = "Hello";
ViewData["Address"] = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return 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>
ViewBag
對象為儲存在 ViewData
里的對象提供動態訪問。這樣使用起來就更方便了,因為不需要轉換。與上面的例子一樣,在視圖中採用了 ViewBag
而不是強類型的 Address
實例:
@ViewBag.Greeting World! // 手動高亮
<address>
@ViewBag.Address.Name<br /> // 手動高亮
@ViewBag.Address.Street<br /> // 手動高亮
@ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode // 手動高亮
</address>
由於二者引用的是相同的底層
ViewData
集合,在你讀取和寫入值的時候,可以根據方便與否來協調混用ViewData
和ViewBag
。
動態視圖
對於沒有聲明模型類型但給它們傳遞了模型實例的視圖,可以動態地引用這個實例。例如,如果將一個 Address
實例傳給了一個並沒有聲明 @model
的視圖,那麼這個視圖還是能夠像下麵展示的那樣去引用這個實例的屬性:
<address>
@Model.Street<br />
@Model.City, @Model.State @Model.PostalCode<br />
<abbr title="Phone">P:</abbr>
425.555.0100
</address>
這種特性能提供一些靈活性,但無法提供編譯保護和智能提示。如果屬性並不存在,頁面將在運行時出錯。
更多視圖特性
Tag helpers便於給已有的 HTML 標記添加服務端行為,不需要視圖中的自定義代碼或助手代碼。Tag helper 是作為 HTML 元素的屬性啟用的,會被不認識它們的編輯器忽略掉,使得視圖標簽可以被很多的工具編輯和渲染。Tag helper 有很多用途,尤其是非常便於使用表單 。
可以用很多內置的HTML Helpers生成自定義的 HTML 標記,更複雜的 UI 邏輯(可能有它自己的數據需求)可以在 View Components中封裝。與控制器和視圖一樣,視圖組件也提供關註點分離,並且無需操作和視圖就可以處理通用 UI 元素用到的數據。
與 ASP.NET Core 的很多方面一樣,視圖也支持依賴註入,允許將服務註入到視圖。