在以前的幾篇中,咱們大概介紹瞭如何建立一個asp.net core mvc項目以及http請求如何被路由轉交給對應的執行單元。這一篇咱們將介紹一下控制器與視圖直接的關係。html
這裏的視圖不是數據庫裏的視圖,是一種展現技術。在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
兩個文件(注意,有個前置下劃線)。c#
咱們知道,在cshtml文件中,雖然極大的減小了服務器代碼,可是有時候沒法避免的使用一些C#代碼。那麼就會產生一個問題,不少類都有本身的命名空間,若是咱們在某個或某幾個或某些視圖中須要訪問這些類和方法,那麼一個視圖一個視圖的寫引用有點不太現實,由於這太繁瑣了。服務器
因此asp.net core mvc 設置了在名爲_ViewImports.cshtml的文件中添加引用,則在Views下全部視圖中都生效。那麼,先來看看這個文件裏有啥吧:mvc
@using MvcWeb @using MvcWeb.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
能夠看到,這裏引用了項目的命名空間和項目下Modes命名空間的全部內容。由於咱們以前建立的測試項目名稱就是 MvcWeb。asp.net
最後一行是一個 cshtml標記引用,第一個星號表示當前項目的全部TagHelper實現都引用,後面的表示引入aps.net core mvc內置的TagHelper。佈局
關於 TagHelper,這篇就先不介紹了。測試
_ViewStart.cshtml
做用從名字中可見一二,這個文件用來配置一些在視圖剛開始加載時的一些配置內容。先看一下,默認的裏面是什麼吧:spa
@{ Layout = "_Layout"; }
先作個介紹,@符號後面用一對大括號包裹,裏面是C# 代碼。也就是說 Layout = "_Layout"
,這行的意思是給某個名爲Layout的屬性設置值爲_Layout
。
那麼,Layout的屬性是哪裏的呢?
對於asp.net core mvc而言,一個視圖也是一個類只不過這個類是動態生成的,不是一個由程序員編寫出來的類,可是這個類繼承自:
namespace Microsoft.AspNetCore.Mvc.Razor { public abstract class RazorPageBase : IRazorPage { } }
Layout正好是這個類的一個屬性,表示視圖是否使用了某個佈局頁。因此上面的代碼表示,Views裏的新建視圖,默認是使用名爲_Layout
的視圖做爲佈局頁。
固然,這個頁面不僅有這個做用,小夥伴們能夠本身嘗試下哦。
在上一節中,咱們指定了一個佈局頁的名稱。佈局頁也是視圖中的一種,但咱們也只指定了名稱,但沒有指定路徑。asp.net core是如何發現這個名稱的視圖呢?
asp.net core 會按照如下順序查找對應的視圖文件:
因此,_Layout
也會按照這個順序查找,爲了不沒必要要的混淆,咱們只在Shared目錄下寫了_Layout.cshtml
。這也是一般的作法,該文件表示一個全局的佈局頁。
在上一篇《【asp.net core 系列】2 控制器與路由的恩怨情仇》中,咱們介紹了三種建立控制器的方法,而且最後推薦使用名字以Controller結尾並繼承Controller類的寫法。我將在這裏爲你們再次講解爲何推薦這樣寫:
嗯,暫時就這兩點。別看少,可是這很重要。
在以前介紹的時候,有提到過當咱們訪問一個URL的時候,路由會自動爲咱們尋找到對應的可執行代碼單元。可是,沒有進一步內容的介紹。當咱們尋找到對應的可執行代碼單元也就是Action以後,Action進行一系列的處理,會對這個請求作出響應。有一種響應就是返回一個展現頁面,也就是View。
那麼,如何返回一個View呢?
建立一個控制器,名爲ViewDemoController
,並添加一個方法Index
,返回類型爲IActionResult
:
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/
應該是相似的頁面。
IActionResult 是一個接口,表示是一個Action的處理結果,在這裏能夠理解爲固定寫法。
在控制器裏,View 方法表示使用一個視圖進行渲染,默認是使用方法同名的視圖。固然,既然是默認的,那就必定有不默認的時候。對的,View方法提供了幾個重載版本,這些重載版本里有一個名字爲viewName
的參數,這個參數就是用來指定視圖名稱的。
那麼,咱們能夠指定哪些視圖名稱:
這兩種都是不用攜帶路徑的視圖名,能夠省略文件擴展名(cshtml)。
固然,還能夠指定其餘路徑下的視圖文件,如:
Views/Home/About.cshtml
表示從根目錄下查找到這個視圖,這種寫法必須指定擴展名../Manage/Index
表示在Manage控制器目錄下的Index以前介紹瞭如何使用視圖、如何指定視圖名稱,可是還缺最關鍵的一步,那就是如何給視圖傳遞數據。
一般狀況下,Action方法中給視圖傳遞數據,只有這三種是推薦的:
Controller類有一個屬性是 ViewData,它的聲明以下:
public ViewDataDictionary ViewData { get; set; }
能夠看到這是一個字典型的屬性,因此給它賦值是這樣使用的:
public IActionResult Index() { ViewData["Title"] = "ViewDemo"; return View(); }
ViewBag也是 Controller類的一個屬性,它的聲明以下:
public dynamic ViewBag { get; }
能夠看到這是一個動態類,實際上ViewBag裏的數據與ViewData是互通的,換句話說就是ViewBag是對ViewData的一次封裝,二者並無實際上的區別。賦值使用:
public IActionResult Index() { ViewBag.Name = "小李"; return View(); }
而ViewDataAttribute則與上兩個,不太同樣,這個屬性標註給控制器的屬性上,asp.net core mvc就會把這個屬性的值填充給ViewData,鍵值就是屬性名:
[ViewData] public string AttributeTest{get;set;}
與 ViewData["AttributeTest"]
效果一致。
在View方法的一些重載版本里,須要一個名爲 model的參數,類型是object。這個參數就是一個ViewModel。使用:
在MvcWeb/Models 下添加一個類:
namespace MvcWeb.Models { public class ViewModelTestModel { public string Name{get;set;} public int Age{get;set;} } }
回到剛剛的Index方法裏,建立一個ViewModelTestModel實例,並傳給View方法:
public IActionResult Index() { ViewData["Title"] = "ViewDemo"; ViewBag.Name = "小李"; var model = new ViewModelTestModel { Name = "測試實例", Age = 1 }; return View(model); }
在上一小節中,咱們分別使用ViewData和ViewBag以及ViewModel給視圖傳遞了三個數據,那麼如何在視圖中獲取這三個數據呢?
<h2>@ViewData["Title"]</h2> <!--實際會顯示 <h2>ViewDemo</h2>-->
與字典同樣,@起頭,表示後面跟着一個屬性或者一段C#表達式,並將表達式的結果輸出到頁面上。
ViewBag的訪問與ViewData相似,只不過ViewBag是動態對象,能夠認爲它的類型並無發生改變,繼續按照以前的類型進行使用:
<h4>@ViewBag.Name</h4>
對於ViewModel的使用,View內置了一個dynamic的Model屬性,在不作特殊處理的狀況下,咱們在頁面上使用@Model
會獲得一個dynamic對象(若是傳了ViewModel的話)。雖然也能用,可是這不太友好。
這時候,就須要咱們在視圖的開頭處,添加:
@model ViewModelTestModel
這時候,再使用@Model
的時候,就會自動解析成ViewModelTestModel了。
總體Index.cshtml內容以下:
@model ViewModelTestModel Hello World! <h2>@ViewData["Title"]</h2> <h4>@ViewBag.Name</h4> @Model.Name + @Model.Age
而後重啓服務後,刷新頁面,會看到相似的內容:
咱們在這一篇介紹了視圖的一些概念,並介紹瞭如何使用控制器給視圖傳遞數據。下一篇將講解一下路由的高級做用,如何經過路由攜帶數據。
更多內容煩請關注個人博客《高先生小屋》