1. 程式人生 > >【asp.net core 系列】3 檢視以及檢視與控制器

【asp.net core 系列】3 檢視以及檢視與控制器

# 0.前言 在之前的幾篇中,我們大概介紹瞭如何建立一個asp.net core mvc專案以及http請求如何被路由轉交給對應的執行單元。這一篇我們將介紹一下控制器與檢視直接的關係。 # 1. 檢視 這裡的檢視不是資料庫裡的檢視,是一種展示技術。在asp.net core mvc專案中檢視是指以cshtml做副檔名的檔案,通常在Views資料夾。 那麼現在我們進到之前建立的測試專案 MvcWeb的Views目錄下,如果小夥伴們沒有做修改的話,能看到如下的目錄結構: ``` ├── Home │ ├── Index.cshtml │ └── Privacy.cshtml ├── Shared │ ├── Error.cshtml │ ├── _Layout.cshtml │ └── _ValidationScriptsPartial.cshtml ├── _ViewImports.cshtml └── _ViewStart.cshtml ``` 在Views根目錄下,有兩個檔案分別是:`_ViewImports.cshtml` 、` _ViewStart.cshtml` 兩個檔案(注意,有個前置下劃線)。 ## 1.1 在檢視中引用名稱空間 我們知道,在cshtml檔案中,雖然極大的減少了伺服器程式碼,但是有時候無法避免的使用一些C#程式碼。那麼就會產生一個問題,很多類都有自己的名稱空間,如果我們在某個或某幾個或某些檢視中需要訪問這些類和方法,那麼一個檢視一個檢視的寫引用有點不太現實,因為這太繁瑣了。 所以asp.net core mvc 設定了在名為_ViewImports.cshtml的檔案中新增引用,則在Views下所有檢視中都生效。那麼,先來看看這個檔案裡有啥吧: ```csharp @using MvcWeb @using MvcWeb.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers ``` 可以看到,這裡引用了專案的名稱空間和專案下Modes名稱空間的所有內容。因為我們之前建立的測試專案名稱就是 MvcWeb。 最後一行是一個 cshtml標記引用,第一個星號表示當前專案的所有TagHelper實現都引用,後面的表示引入aps.net core mvc內建的TagHelper。 > 關於 TagHelper,這篇就先不介紹了。 ## 1.2 ViewsStart `_ViewStart.cshtml` 作用從名字中可見一二,這個檔案用來配置一些在檢視剛開始載入時的一些配置內容。先看一下,預設的裡面是什麼吧: ```html @{ Layout = "_Layout"; } ``` 先做個介紹,@符號後面用一對大括號包裹,裡面是C# 程式碼。也就是說 `Layout = "_Layout"`,這行的意思是給某個名為Layout的屬性設定值為`_Layout`。 那麼,Layout的屬性是哪裡的呢? 對於asp.net core mvc而言,一個檢視也是一個類只不過這個類是動態生成的,不是一個由程式設計師編寫出來的類,但是這個類繼承自: ```c# namespace Microsoft.AspNetCore.Mvc.Razor { public abstract class RazorPageBase : IRazorPage { } } ``` Layout正好是這個類的一個屬性,表示檢視是否使用了某個佈局頁。所以上面的程式碼表示,Views裡的新建檢視,預設是使用名為`_Layout`的檢視作為佈局頁。 當然,這個頁面不只有這個作用,小夥伴們可以自己嘗試下哦。 ## 1.3 檢視檢索 在上一節中,我們指定了一個佈局頁的名稱。佈局頁也是檢視中的一種,但我們也只指定了名稱,但沒有指定路徑。asp.net core是如何發現這個名稱的檢視呢? asp.net core 會按照以下順序查詢對應的檢視檔案: - Views/[ControllerName]/[ViewName].cshtml - Views/Shared/[ViewName].cshtml 所以,`_Layout`也會按照這個順序查詢,為了避免不必要的混淆,我們只在Shared目錄下寫了`_Layout.cshtml`。這也是通常的做法,該檔案表示一個全域性的佈局頁。 # 2. 控制器與檢視的關係 在上一篇《【asp.net core 系列】2 控制器與路由的恩怨情仇》中,我們介紹了三種建立控制器的方法,並且最後推薦使用名字以Controller結尾並繼承Controller類的寫法。我將在這裡為大家再次講解為什麼推薦這樣寫: - 以Controller結尾,可以很明確的告訴其他人或者未來的自己這是一個控制器,不是別的類 - 繼承Controller,是因為Controller類為我們提供了控制器用到的屬性和方法 嗯,暫時就這兩點。別看少,但是這很重要。 ## 2.1 使用檢視 在之前介紹的時候,有提到過當我們訪問一個URL的時候,路由會自動為我們尋找到對應的可執行程式碼單元。但是,沒有進一步內容的介紹。當我們尋找到對應的可執行程式碼單元也就是Action之後,Action進行一系列的處理,會對這個請求做出響應。有一種響應就是返回一個展示頁面,也就是View。 那麼,如何返回一個View呢? 建立一個控制器,名為`ViewDemoController`,並新增一個方法`Index`,返回型別為`IActionResult`: ```c# using Microsoft.AspNetCore.Mvc; namespace MvcWeb.Controllers { public class ViewDemoController:Controller { public IActionResult Index() { return View(); } } } ``` 其中 View() 表示返回一個View,這View的名稱是 Index,在ViewDemo控制器下。所以,它的路徑應該是: ``` Views/ViewDemo/Index.cshtml ``` 在對應目錄建立該檔案,然後在檔案裡隨便寫一些內容,之後啟動專案(專案的埠在第一部分就已經修改過了): ``` http://localhost:5006 ``` 然後訪問: ``` http://localhost:5006/ViewDemo/ ``` ![image-20200601225734470](https://img2020.cnblogs.com/other/1266612/202006/1266612-20200602222207554-1555275627.png) 應該是類似的頁面。 > IActionResult 是一個介面,表示是一個Action的處理結果,在這裡可以理解為固定寫法。 ## 2.2 指定檢視 在控制器裡,View 方法表示使用一個檢視進行渲染,預設是使用方法同名的檢視。當然,既然是預設的,那就一定有不預設的時候。對的,View方法提供了幾個過載版本,這些過載版本里有一個名字為`viewName`的引數,這個引數就是用來指定檢視名稱的。 那麼,我們可以指定哪些檢視名稱: - 同一個控制器資料夾下的其他檢視 - Shared 資料夾下的檢視 這兩種都是不用攜帶路徑的檢視名,可以省略副檔名(cshtml)。 當然,還可以指定其他路徑下的檢視檔案,如: - `Views/Home/About.cshtml `表示從根目錄下查詢到這個檢視,這種寫法必須指定副檔名 - `../Manage/Index` 表示在Manage控制器目錄下的Index ## 2.3 給檢視傳遞資料 之前介紹瞭如何使用檢視、如何指定檢視名稱,但是還缺最關鍵的一步,那就是如何給檢視傳遞資料。 通常情況下,Action方法中給檢視傳遞資料,只有這三種是推薦的: - 使用ViewData - 使用ViewDataAttribute - 使用ViewBag - 使用ViewModel Controller類有一個屬性是 ViewData,它的宣告如下: ```c# public ViewDataDictionary ViewData { get; set; } ``` 可以看到這是一個字典型的屬性,所以給它賦值是這樣使用的: ```c# public IActionResult Index() { ViewData["Title"] = "ViewDemo"; return View(); } ``` ViewBag也是 Controller類的一個屬性,它的宣告如下: ```c# public dynamic ViewBag { get; } ``` 可以看到這是一個動態類,實際上ViewBag裡的資料與ViewData是互通的,換句話說就是ViewBag是對ViewData的一次封裝,兩者並沒有實際上的區別。賦值使用: ```c# public IActionResult Index() { ViewBag.Name = "小李"; return View(); } ``` 而ViewDataAttribute則與上兩個,不太一樣,這個屬性標註給控制器的屬性上,asp.net core mvc就會把這個屬性的值填充給ViewData,鍵值就是屬性名: ```c# [ViewData] public string AttributeTest{get;set;} ``` 與 `ViewData["AttributeTest"]`效果一致。 在View方法的一些過載版本里,需要一個名為 model的引數,型別是object。這個引數就是一個ViewModel。使用: 在MvcWeb/Models 下新增一個類: ```c# namespace MvcWeb.Models { public class ViewModelTestModel { public string Name{get;set;} public int Age{get;set;} } } ``` 回到剛剛的Index方法裡,建立一個ViewModelTestModel例項,並傳給View方法: ```c# public IActionResult Index() { ViewData["Title"] = "ViewDemo"; ViewBag.Name = "小李"; var model = new ViewModelTestModel { Name = "測試例項", Age = 1 }; return View(model); } ``` ## 2.4 在檢視中使用 在上一小節中,我們分別使用ViewData和ViewBag以及ViewModel給檢視傳遞了三個資料,那麼如何在檢視中獲取這三個資料呢? ```html

@ViewData["Title"]

``` 與字典一樣,@起頭,表示後面跟著一個屬性或者一段C#表示式,並將表示式的結果輸出到頁面上。 ViewBag的訪問與ViewData類似,只不過ViewBag是動態物件,可以認為它的型別並沒有發生改變,繼續按照之前的型別進行使用: ```xml

@ViewBag.Name

``` 對於ViewModel的使用,View內建了一個dynamic的Model屬性,在不做特殊處理的情況下,我們在頁面上使用`@Model` 會得到一個dynamic物件(如果傳了ViewModel的話)。雖然也能用,但是這不太友好。 這時候,就需要我們在檢視的開頭處,新增: ```c# @model ViewModelTestModel ``` 這時候,再使用`@Model`的時候,就會自動解析成ViewModelTestModel了。 整體Index.cshtml內容如下: ```html @model ViewModelTestModel Hello World!

@ViewData["Title"]

@ViewBag.Name

@Model.Name + @Model.Age ``` 然後重啟服務後,重新整理頁面,會看到類似的內容: ![image-20200601235928566](https://img2020.cnblogs.com/other/1266612/202006/1266612-20200602222207773-914159157.png) # 3. 總結 我們在這一篇介紹了檢視的一些概念,並介紹瞭如何使用控制器給檢視傳遞資料。下一篇將講解一下路由的高階作用,如何通過路由攜帶資料。 > 更多內容煩請關注[我的部落格《高先生小屋》](https://www.attachie.club) ![file](https://img2020.cnblogs.com/other/1266612/202006/1266612-20200602222208174-281120