ASP.NET MVC高效構建Web應用- 商品搜索 - 京東
視圖(V)是一個動態生成HTML頁面的模板,它負責通過用戶界面展示內容。本節將修改HelloWorldController類,并使用視圖模板文件,以干凈地封裝生成對客戶端的HTML響應的過程。
我們將使用Razor視圖引擎創建視圖模板文件。基于Razor的視圖模板具有.cshtml文件擴展名,并提供一種使用C#創建HTML輸出的優雅方法。Razor將編寫視圖模板時所需的字符數和擊鍵次數降至最低,并支持快速、流暢的編碼工作流。目前,我們只需知道,Razor是MVC框架視圖引擎,可以用來創建視圖模板文件。
3.3.1? 新建項目添加視圖文件
這里,我們可以復制一份例3.1代碼作為本節的實例,然后基于此項目逐漸豐富內容。
【例3.2】將視圖添加到MVC項目
(1)復制一份例3.1的項目文件夾test到磁盤另外某個目錄,然后進入復制后的test文件夾,雙擊test.sln打開項目。打開HelloWorldController.cs文件,查看VS向導生成的Index方法,代碼如下:
public string Index(){return "This is my <b>default</b> action...";}
當前,Index方法返回硬編碼的含HTML的字符串。我們更改一下 Index 方法,代碼如下所示:
public ActionResult Index() //方法的類型改為ActionResult{return View(); //返回View方法的結果}
我們使用視圖模板生成對瀏覽器的HTML響應,此時Index方法返回的是ActionResult(或派生自 ActionResult)的類,而不是字符串等基元類型。View方法是控制器類(即類Controller)的一個內部方法,聲明如下:
protected internal ViewResult View();
由于HelloWorldController類繼承自類Controller,因此可以使用類Controller中的View方法。該方法創建一個ViewResult對象,該對象將視圖呈現給響應。
我們知道,MVC中的控制器負責處理HTTP請求并生成響應結果,現在我們返回一個ViewResult對象作為響應結果,說白了,就是給客戶端瀏覽器一個視圖。語句return View();告訴方法Index應使用視圖文件來呈現對瀏覽器的響應。但由于未顯式指定要使用的視圖文件的名稱,ASP.NET MVC就默認使用\Views\HelloWorld文件夾中的Index.cshtml視圖文件。那么,接下來我們要添加一個Index.cshtml文件。
(2)準備添加視圖文件Index.cshtml。在解決方案資源管理器中,右鍵單擊“Views\HelloWorld”文件夾并單擊“添加”,然后單擊“具有布局的MVC 5視圖頁(Razor)”,此時出現“指定項名稱”窗口,我們在“項名稱”文本框中輸入Index,如圖3-13所示。
圖3-13
點擊“確定”按鈕,出現“選擇布局頁”對話框,如圖3-14所示。
圖5?10
在“選擇布局頁”對話框中,接受默認_Layout.cshtml,然后單擊“確定”,此時將創建\test\Views\HelloWorld\Index.cshtml文件。在上面的對話框中,在左窗格中選擇Views\Shared文件夾,如果另一個文件夾中有一個自定義布局文件,則可以選擇它。
在VS中雙擊剛才新增的Index.cshtml,添加代碼如下:
@{Layout = "~/Views/Shared/_Layout.cshtml";}@{ ViewBag.Title = "my mvc"; }<h2>hi</h2><p>Hello from our View Template!</p>
粗體部分就是我們添加的。符號@是視圖引擎Razor中的一個標記,表示用來插入一段服務器端的編程語言代碼,這里是C#語言,也就是插入一段C#代碼。VS MVC的視圖引擎有兩種:ASPX(C#)和Razor(cshtml),建議以后都使用Razor視圖引擎(VS2017中已經默認Razor引擎了)。原來<% %>用于ASPX引擎視圖頁中,作為插入C#代碼的標識,而在Razor中用更簡潔的@代替了。這樣就可以在cshtml文件中使用C#代碼了。所以我們知道,{ ViewBag.Title = "my mvc";}就是一段C#代碼,意思是把字符串"my mvc"賦值給ViewBag.Title。ViewBag.Title就相當于一個全局變量,程序運行時,網頁標題會取值這個全局變量值,這樣ViewBag.Title所存儲的字符串就可以顯示在網頁標題上了。我們可以打開Shared文件夾下的_Layout.cshtml,這個文件稱為布局文件,在這個文件里有這么一句:
<title>@ViewBag.Title - 我的ASP.NET應用程序</title>
@ViewBag.Title就是顯示全局變量ViewBag.Title中的內容。@不能省略,否則就是直接顯示“ViewBag.Title”本身了。
再回到Index.cshtml,最后2行HTML代碼沒啥好講的,就是顯示在網頁上的普通字符串而已。<h2>是HTML中的一個標簽,代表heading level 2,用于表示一個二級標題。<p>表示段落標簽,是HTML中用于定義段落的基本元素。
現在運行項目,在瀏覽器中輸入URL:https://localhost:44308/HelloWorld/Index,運行結果如圖3-15所示。
圖3-15
可以看到,“my mvc”顯示在瀏覽器標題欄上,而網頁中也正確顯示了“hi”和“Hello from our View Template!”兩個硬編碼的字符串。網頁上方的“應用程序名稱”“主頁”“關于”和“聯系方式”是4個網址鏈接,點擊它們可以打開新的網頁,這4個鏈接是布局自動生成的,下面我們來改變一下布局。
3.3.2? 更改視圖和布局頁面
首先,需要更改頁面頂部的“應用程序名稱”鏈接。繼續在剛才的項目中,轉到解決方案資源管理器中的/Views/Shared文件夾,然后雙擊打開_Layout.cshtml文件。此文件稱為布局頁,它位于所有其他頁面使用的共享文件夾中。
布局模板使你能夠在一個位置指定網站的HTML容器布局,然后將它應用到網站中的多個頁面。查找@RenderBody()行。RenderBody是一個占位符,在其中顯示你創建的所有視圖特定的頁面,“包裝”在布局頁面中。例如,如果選擇“關于”鏈接,Views\Home\About.cshtml視圖將在方法內RenderBody呈現。
如果我們在布局頁文件_Layout.cshtml中修改網頁名稱或網址鏈接,那將會在所有網頁上發生效果。比如,我們在_Layout.cshtml中,修改<title></title>之間的內容如下:
<title>@ViewBag.Title - Movie App</title>
意思就是修改一下標題。然后再把“ActionLink("應用程序名稱",…)”這一行的內容修改如下:
@Html.ActionLink("MVC Movie", "Index", "Movies", null, new { @class = "navbar-brand" })
意思就是修改一下網址鏈接的標題。此時運行項目,我們可以看到在標題欄中的頁面標題也變為“Home Page - Movie App”了,而且主頁上的第一個鏈接名稱變為“MVC Movie”了,如圖3-16所示。
這說明修改生效了。再單擊“關于”鏈接,你也會看到該頁面顯示“MVC Movie”以及標題欄中的標題依舊有“Movie App”這樣的字符串,如圖3-17所示。
???
這就說明,我們能夠在布局頁文件_Layout.cshtml中進行更改,并讓網站上的所有頁面都反映新標題。那為何會所有頁面都反映新標題呢?這是因為所有網頁的源代碼都包含了_Layout.cshtml了。比如,當我們第一次添加Views\HelloWorld\Index.cshtml文件時,它自動包含以下代碼:
@{Layout = "~/Views/Shared/_Layout.cshtml";}
這幾行代碼就是顯式地為Index.cshtml設置布局頁_Layout.cshtml。那為何會自動包含這幾行代碼呢?這是因為在Views\_ViewStart.cshtml文件中指定了。Views\_ViewStart.cshtml文件定義了所有視圖將使用的通用布局。如果不想讓某個頁面使用通用布局,我們可以注釋掉或從該頁面文件中刪除該代碼。比如,在Views\HelloWorld\Index.cshtml中注釋掉布局引用:
@*@{Layout = "~/Views/Shared/_Layout.cshtml";}*@
其中是@*和*@用于注釋。如果不想注釋,也可以可以使用Layout屬性設置不同的布局視圖,或將它設置為null,這樣將不會使用任何布局文件。
3.3.3? 更改視圖標題
了解了布局的來龍去脈。現在,讓我們更改Index視圖的標題,在項目中雙擊打開Views/HelloWorld/Index.cshtml,修改ViewBag.Title的賦值,代碼如下:
@{ViewBag.Title = "Movie List";}
圖3-18 |
ViewBag是一個可以在控制器和視圖之間傳遞任意類型對象的動態對象,Title是ViewBag中的一個專門存儲字符串的屬性,除它以外,還有其他屬性,以后會慢慢接觸到。我們可以通過在控制器中設置ViewBag的屬性值,然后在視圖中使用ViewBag 來訪問這些屬性值。例如,在控制器中設置ViewBag.Title = "My Title",然后在視圖中使用@ViewBag.Title 來訪問這個屬性值,這樣就可以將數據從控制器傳遞到視圖中。當然這種使用方式也可以應用在多個cshtml文件中,就像現在,我們在HelloWorld/Index.cshtml中將字符串"Movie List"賦值給ViewBag.Title,那么在Views/Shared/_Layout.cshtml文件中的代碼:
<title>@ViewBag.Title - Movie App</title>
就可以引用到ViewBag.Title所存儲的最新內容了。使用此方法ViewBag,可以輕松地在視圖模板和布局文件之間傳遞其他參數。我們按Ctrl+F5運行項目,然后在瀏覽器地址欄中輸入URL:https://localhost:44308/HelloWorld/,運行結果如圖3-18所示。
可以看到瀏覽器標題已被更改為“Movie List - Movie App”。如果在瀏覽器中未看到更改,則可能正在查看緩存的內容,此時可以在瀏覽器中按 Ctrl+F5強制加載來自服務器的響應。瀏覽器標題使用的ViewBag.Title是我們在Index.cshtml 視圖模板中設置的,并在布局文件_Layout.cshtml中添加附加的“- Movie App”所創建。現在,我們學會了通過Index.cshtml 和_Layout.cshtml來修改瀏覽器標題了。其實,憑借布局文件可以很容易地對應用程序中所有頁面進行更改。
不過,本例顯示的數據(即“Hello from our View Template!”消息)是硬編碼的。MVC應用程序有一個“V”(視圖),而我們已有一個“C”(控制器),但還沒有“M”(模型)。以后,我們將學習如何創建數據庫并從中檢索模型數據,而不是直接硬編碼數據。
3.3.4? 將數據從控制器傳遞給視圖
在學習數據庫并討論模型之前,讓我們先討論如何將信息從控制器傳遞到視圖。調用控制器類以響應傳入的URL 請求,控制器類通過編寫代碼,用于處理傳入瀏覽器請求、從數據庫中檢索數據,并最終決定發送回瀏覽器的響應類型。最后,我們可以從控制器使用視圖模板來生成HTML響應并設置瀏覽器的格式。
控制器負責提供所需的任何數據或對象,以便視圖模板向瀏覽器呈現響應。最佳做法是視圖模板絕不應該執行業務邏輯或直接與數據庫交互。相反,視圖模板應僅處理控制器提供給它的數據。保持這種“關注點分離”有助于保持代碼干凈、可測試且更易于維護。
我們回顧一下類HelloWorldController中的Welcome方法,目前代碼如下:
public string Welcome(string name,float height, int age = 10){return HttpUtility.HtmlEncode("Hello " + name + ", your height:"+height+" and age:"+age);}
可見,參數name、height和age直接輸出到瀏覽器。我們將控制器更改為使用視圖模板,而不是讓控制器以字符串的形式呈現此響應。視圖模板將生成動態響應,這意味著你需要將適當的數據從控制器傳遞給視圖以生成響應。為此,我們可以讓控制器將視圖模板所需的動態數據(參數)存儲在ViewBag,隨后視圖模板可以訪問的對象中ViewBag。
打開HelloWorldController.cs文件,并在Welcome方法中為ViewBag對象添加 name和 height的值。ViewBag是一個動態對象,這意味著可以將任何你想要的對象放入其中。ASP.NET MVC模型綁定系統會自動將命名參數(name和height)從地址欄中的查詢字符串映射到方法中的參數。修改后的Welcome方法如下所示:
public ActionResult Welcome(string name,float height, int age = 10){ViewBag.name = "Hello " + name;ViewBag.h = "Height:"+ height.ToString();ViewBag.age = age;return View();}
現在,ViewBag對象包含將自動傳遞給視圖的數據。接下來,需要一個歡迎視圖頁來展現這些參數數據。語句return View();告訴方法Welcome應使用視圖文件來呈現對瀏覽器的響應,但由于未顯式指定要使用的視圖文件的名稱,ASP.NET MVC就默認使用\Views\HelloWorld文件夾中的Welcome.cshtml視圖文件。接下來,我們要添加一個Welcome.cshtml文件。右鍵單擊 Views\HelloWorld文件夾并單擊“ 添加”,然后單擊“帶有布局的MVC 5視圖頁(Razor)”,在“指定項的名稱”對話框中,輸入“Welcome”,然后單擊“ 確定”。在“選擇布局頁”對話框中,接受默認_Layout.cshtml,然后單擊“確定”。此時,將會在磁盤上創建test\Views\HelloWorld\ Welcome.cshtml文件。下面我們在Welcome.cshtml文件中添加代碼如下:
@{ViewBag.Title = "Welcome";}<h2>You are welcome!</h2><ul>@for (int i = 0; i < ViewBag.age; i++){<li>@ViewBag.name,@ViewBag.h</li>}</ul>
首先在頁面上顯示字符串“You are welcome!”,然后使用一個for循環,該循環中顯示的內容由@ViewBag.name和@ViewBag.h決定,并且它們的實際值由用戶在URL中指定。運行項目,在瀏覽器地址欄中輸入URL:
https://localhost:44308/helloWorld/welcome?name=tom&height=1.18&age=5
運行結果如圖3-19所示。
圖3-20
可以看到實際數據從 URL中獲取,并使用模型綁定器傳遞給控制器。控制器將數據打包到對象中,ViewBag并將該對象傳遞給視圖。然后,視圖以HTML形式向用戶顯示數據。在這個實例中,我們使用ViewBag對象將數據從控制器傳遞到視圖。