在這一章中,我們將學習如何使用基架快速搭建和運行一個簡單的Microsoft ASP.NET MVC Web站點。在我們馬上投入學習和編碼之前,我們首先了解一些有關ASP.NET MVC和Entity Framework的背景信息,然后再詳細學習如何搭建開發環境。
1.1 MVC和ASP.NET MVC
這本書涵蓋Microsoft版本的MVC,即ASP.NET MVC。在寫本書的時候,ASP.NET MVC的生產版本為MVC5,因此,本書的示例代碼都使用ASP.NET MVC 5編寫。在本書中有一章內容涵蓋ASP.NET Core 1.0 MVC (MVC 6)。
MVC這三個大寫字母分別表示Model-View-Controller(模型-視圖-控制器),是一種廣泛使用的軟件開發設計模式。ASP.NET MVC由以下基本模塊組成:
- Models:是一些表示應用程序數據的類,這些類通常稱之為普通CLR對象(Plain Old CLR Objects, POCOs)。這些類也用來封裝和執行一些業務邏輯,比如,我們稍后看到的購物車的業務邏輯。
- Views:是一些用於生成HTML的模板文件,生成的HTML文件將會被發送到瀏覽器。視圖(View)通常用於展示從模型(Model)獲取的數據。盡管視圖(View)可以包含一些決定哪些HTML可以被生成的邏輯,但不應該包含任何業務邏輯。
- Controllers:是一些用於處理輸入請求的類,這些類可以從模型(Model)獲取數據,並將這些數據傳遞給視圖(View),最終在視圖(View)生成的HTML中顯示。控制器(Controller)可能會包含一些根據請求中的某些信息來過濾數據的邏輯。比如,我們可以根據傳遞給控制器(Controller)方法的參數(該參數的值來自於客戶端請求)來生成查詢。
譯者注:在本書后續翻譯過程中,將會把Model翻譯成模型、View翻譯成視圖、Controller翻譯成控制器,不再使用英文描述。
在本書中的示例代碼有助於加深我們對模型、視圖和控制器定義的理解,並在合適的時機使用更加高級的概念,比如視圖模型(View Model)。
MVC起源於70年代后期的Smalltalk項目,從此之后不斷被更新並應用於多個技術領域。MVC的主要原則是要創建一個可分層的、可測試的以及可維護的應用程序體系架構。MVC的特點之一就是比較適合做單元測試,這主要得益於模型、視圖和控制器的划分。單元測試在本書中沒有涉及,如果想對單元測試有一個深入的理解,推薦大家閱讀Adam Freeman的PRO ASP.NET MVC(中文名稱:精通ASP.NET MVC 5)一書。
1.2 Entity Framework和Code First(代碼優先)
Entity Framework (EF)是一個對象關系映射(object relational mapping, ORM)框架,該框架是.NET Framework的一部分。本書將通篇使用Entity Framework的Code First方法編寫類及它們之間的關系,然后在不使用任何SQL語句的情況下,生成數據庫及對應的表。在編寫本書時,Entity Framework可用版本為EF 6,然而在本書中有一章會涉及使用EF 7版本。在本書中的所有示例代碼使用的都是SQL Server,但是,Entity Framework也可以用於其他關系型數據庫,比如Oracle。
1.2.1 將Code Frist應用於現有數據庫
正如前面鎖提到的,Code First是使用Entity Framework的一種方法,使用該方法可以允許我們首先編寫Model類,然后根據模型類來生成數據庫及對應的表,這比較適合數據庫不存在的新建項目。但是,從EF 6.1開始,Code First也可以用於已存在的數據庫,並且可以根據已存在的數據庫生成Model類。這個主題我們會在本書后面章節深入講解。
1.3 Web開發的軟件需求
本書所使用的是Visual Studio 2015 Community版本,這個可以在Microsoft站點免費下載,該版本幾乎包含了Visual Studio 2015付費版本的所用功能,我們將使用這個版本編寫本書的所有代碼。在本書中我們還將使用Google的Chrome瀏覽器來運行和測試我們編寫的代碼,之所以使用Chrome瀏覽器,是因為該瀏覽器提供了非常優秀的針對開發人員工具。我們還推薦大家最好在擁有4GB內存的Windows PC機上運行Visual Studio。
我們可以在以下鏈接中下載Visual Studio 2015 Community版本:https://www.visualstudio.com/zh-hans/downloads/
注意:當我們安裝Visual Studio 2015 Community的時候會自動安裝SQL LocalDB,但是,在Windows 10系統上,可能需要我們單獨安裝SQL LocalDB。SQL Server Express可以在以下鏈接中下載:https://www.microsoft.com/zh-CN/download/details.aspx?id=42299
1.4 創建項目
我們要做的第一件事就是使用Visual Studio創建一個使用ASP.NET MVC和Entity Framework的Web項目。啟動Visual Studio,然后在菜單欄中依次選擇【文件】->【新建】->【項目】,在彈出的“新建項目”窗體中,確保我們選擇了【已安裝】->【模板】->【Visual C#】->【Web】,然后選擇“ASP.NET Web應用程序”項目類型,如圖1-1所示。選擇.NET Framework 4.6.1作為我們.NET的版本。
圖1-1:選擇AS.NET Web應用程序類型
輸入名稱BabyStore,然后點擊“確定”按鈕繼續。我們將看到另一個窗體,如圖1-2所示。在這個窗體中,我們在ASP.NET 4.6.1模板中選擇MVC,並確保身份驗證為個人用戶賬戶。
圖1-2:選擇MVC模板選項
點擊“確定”按鈕創建項目,一旦項目創建完畢,我們將會看到一個寫有“你的ASP.NET應用程序”的頁面。關閉這個文件,因為我們不會用到它。看一下在Visual Studio右側的解決方案資源管理器,Visual Studio使用一個名為基架的過程自動生成了一個基本的MVC項目,我們將使用這個項目作為我們項目的入口點。
在解決方案資源管理器中展開Controllers、Models和Views文件夾,如圖1-3所示。在Models文件夾下創建的文件我們將在后續的身份驗證中用到。在這一章中,我們將學習HomeController類和它相關的視圖。
圖1-3:展開Controllers、Models和Views文件夾的解決方案資源管理器
1.4.1 查看Web站點
從Visual Studio菜單欄中,選擇【調試】->【開始執行(不調試)】,Web站點將會在Visual Studio所使用的瀏覽器中打開,如圖1-4所示。要想改變所使用的瀏覽器,只需要在Visual Studio菜單欄的第二行中的下拉列表中選擇一個不同的瀏覽器即可。
注意:這個Web站點在運行時會使用Visual Studio賦給的一個隨機端口。URL的通常模式為http://localhost:port/Controller/Action/AdditionalParameters(注:此處譯者將http://localhost:port/Controller/View/AdditionalParameters中的View修正為Action)。當這個站點啟動時,我們看到在URL中並沒有顯示控制器名或者動作方法名,這是因為在這個示例中,默認調用了Home控制器中的Index動作(Action)方法,而在Index動作方法中返回的是一個名為Index的視圖。
圖1-4:自動創建的MVC Web站點
1.4.2 主頁是如何工作的
在圖1-4中之所以顯示主頁,是因為我們向Web站點發送了一個URL為/Home/Index的請求,之所以這個URL沒有在瀏覽器的地址欄中顯示,是因為它是應用程序啟動時的默認URL。如果我們在圖1-4中的URL后面添加/Home/Index,然后回車,會發現所顯示的頁面沒有發生改變。
上述URL告訴MVC Web應用程序,一個客戶端請求被發送給Home控制器的Index動作方法。該動作方法在HomeController.cs文件中定義,如下面代碼所示。該動作方法只包含一行簡單的代碼return View(),這行代碼告訴Web站點要打開相對應的視圖文件,在這個示例中,這個對應的視圖文件是Views\Home\文件夾下的Index.cshtml。按照約定,ASP.NET MVC控制器的動作方法的默認視圖文件可以在“Views\控制器名\動作方法名.cshtml”路徑下找到。當然,我們可以改變這種約定,使得動作方法可以打開一個不同的視圖,我們將在本書后續章節講述。包含Index動作方法的Controllers\HomeController.cs文件的內容如下所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace BabyStore.Controllers 8 { 9 public class HomeController : Controller 10 { 11 public ActionResult Index() 12 { 13 return View(); 14 } 15 16 public ActionResult About() 17 { 18 ViewBag.Message = "Your application description page."; 19 20 return View(); 21 } 22 23 public ActionResult Contact() 24 { 25 ViewBag.Message = "Your contact page."; 26 27 return View(); 28 } 29 } 30 }
Views\Home\Index.cshtml文件包含顯示在主頁中的與顯示文本相關的HTML代碼。在這個文件中,我們可以看到好幾個HTML元素都帶有class屬性,這些class屬性的值是Bootstrap的CSS類,這些類控制着Home頁的布局。在后續章節中,我們將學習一些方法來改變Bootstrap以及如何在完全不使用Bootstrap的情況下重新設計我們的站點。
1.4.3 關於頁面、聯系方式頁面和ViewBag
除了注冊和登錄這兩個鏈接之外,在主頁還有另外兩個頁面的鏈接:關於和聯系方式,它們鏈接到的URL分別為/Home/About和/Home/Contact。
這兩個URL鏈接遵循前面所講的約定,即它們會分別調用Home控制器中的About動作方法和Contact動作方法,並且會加載Views\Home目錄下的About.cshtml視圖和Contact.cshtml視圖。
如果我們檢查在上面代碼中的About方法和Contact方法,我們會看到在這兩個方法中都有一行代碼使用了ViewBag。
About動作方法包含的代碼為ViewBag.Message = “Your application description page.”,Contact方法包含的代碼為ViewBag.Message = “Your contact page.”,賦值的這兩句話都顯示在它們各自的視圖中。
如果我們查看About.cshtml文件的代碼,會發現其中有一行代碼為<h3>@ViewBag.Message</h3>,視圖使用這一行代碼來顯示ViewBag的Message屬性的值。當在瀏覽器中顯示時,我們會看到“Your application description page”這行文本,如圖1-5所示。
圖1-5:通過ViewBag由控制器傳遞給About視圖的顯示信息
ViewBag是一個動態對象,用於將數據傳遞給視圖。由於其動態性,不推薦使用ViewBag給視圖傳遞多個數據片段。ViewBag不是強類型,這意味着它可以包含任何數據,因此,我們在視圖中使用它的時候沒有智能提示功能。我們推薦使用強類型視圖模型一次給視圖傳遞多個數據片段。我們將在第三章講述。
1.4.4 路由:Web站點是如何知道我們請求的是哪個控制器的哪個方法
ASP.NET MVC使用ASP.NET的路由控制應用程序如何解釋URL。它也控制着傳遞進來的HTTP請求的目標是哪個控制器的哪個方法,從而顯示哪個視圖。為了解釋它是如何工作的,我們查看一下前面創建應用程序的時候自動生成的默認路由。
打開App_Start文件夾下的RouteConfig.cs文件,在這個文件中的代碼定義了應用程序以何種方式確定請求的URL和哪個控制器的那個動作方法相匹配。代碼如下所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Web.Routing; 7 8 namespace BabyStore 9 { 10 public class RouteConfig 11 { 12 public static void RegisterRoutes(RouteCollection routes) 13 { 14 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 16 routes.MapRoute( 17 name: "Default", 18 url: "{controller}/{action}/{id}", 19 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 ); 21 } 22 } 23 }
我們感興趣的代碼是routes.MapRoute方法,在第17行定義了一個名為“Default”的路由。代碼url: "{controller}/{action}/{id}"指示站點期望第一個片段為控制器的名字,其次是動作的名字(匹配控制器中的方法名),然后是一個名為id的片段。我們待會就會討論id片段,但是,現在我們集中精力在控制器和動作方法片段上。
default命名參數的值告訴應用程序當請求的URL中沒有指定控制器或動作時,就使用其默認值,控制器的默認值是Home,動作的默認值是Index,由此會調用Views\Home下的Index.cshtml視圖。這就是為什么當我們使用不帶任何參數的URL時,Home頁面會加載的原因。
1.4.4.1 使用可選URL的ID參數
為了完成這個非常簡單的默認路由設置的概述,我們修改這個站點的讓它使用可選的ID參數。
打開Controllers文件夾下的HomeController.cs文件,將其中的About方法的代碼修改為下列代碼:
1 public ActionResult About(string id) 2 { 3 ViewBag.Message = "Your application description page. You entered the ID " + id; 4 5 return View(); 6 }
我們告訴這個方法去處理傳遞給它的名為id的參數,這和默認路由設置中的可選的第三個參數名稱相符合。ASP.NET MVC的模型綁定系統會自動將URL中的ID參數映射到About方法的id參數。我們將在后面的章節中詳細講述模型綁定。
現在不調試啟動Web站點導航到關於頁面,然后在URL的后面添加一個ID,如下所示:http://localhost:5073/Home/About/7。
這將把7作為ID參數的值傳遞給About方法,在該方法中我們將這個值添加到了ViewBag中,並在視圖中顯示出來。結果如圖1-6所示。
圖1-6:應用和處理一個可選URL的ID參數
ASP.NET MVC也自動匹配任何與方法參數相匹配的HTTP請求中的參數。這種匹配是不區分大小寫的。比如,我們輸入的URL為http://localhost:5073/Home/About?id=7將會返回和前面相同的結果,這是因為在查詢字符串中的id參數自動匹配About方法的id參數。在第二章我們還會詳細講述。
1.4.5 布局頁的作用
我們可能已經注意到了,當我們導航到不同的頁面,這個站點顯示一樣的頁頭和導航菜單。這種效果是由布局頁來完成的。在Views\Shared\_Layout.cshtml中的布局頁的內容如下所示:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>@ViewBag.Title - 我的 ASP.NET 應用程序</title> 8 @Styles.Render("~/Content/css") 9 @Scripts.Render("~/bundles/modernizr") 10 11 </head> 12 <body> 13 <div class="navbar navbar-inverse navbar-fixed-top"> 14 <div class="container"> 15 <div class="navbar-header"> 16 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 17 <span class="icon-bar"></span> 18 <span class="icon-bar"></span> 19 <span class="icon-bar"></span> 20 </button> 21 @Html.ActionLink("應用程序名稱", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) 22 </div> 23 <div class="navbar-collapse collapse"> 24 <ul class="nav navbar-nav"> 25 <li>@Html.ActionLink("主頁", "Index", "Home")</li> 26 <li>@Html.ActionLink("關於", "About", "Home")</li> 27 <li>@Html.ActionLink("聯系方式", "Contact", "Home")</li> 28 </ul> 29 @Html.Partial("_LoginPartial") 30 </div> 31 </div> 32 </div> 33 <div class="container body-content"> 34 @RenderBody() 35 <hr /> 36 <footer> 37 <p>© @DateTime.Now.Year - 我的 ASP.NET 應用程序</p> 38 </footer> 39 </div> 40 41 @Scripts.Render("~/bundles/jquery") 42 @Scripts.Render("~/bundles/bootstrap") 43 @RenderSection("scripts", required: false) 44 </body> 45 </html>
如果我們打開這個文件,我們會看到它包含了站點導航的一些HTML元素。在該文件中的@RenderBody()方法會將請求的視圖內容插入到布局標記之中。
Views\_ViewStart.cshtml文件中的內容指定了Web站點使用Views\Shared\_Layout.cshtml文件作為主布局頁。框架會將此文件的內容視為視圖的一部分,因此可以有效地將其內容添加到每個視圖的開始部分。下面的代碼顯示了_ViewStart.cshtml文件的內容,它指定我們的站點將使用哪個布局頁。
1 @{ 2 Layout = "~/Views/Shared/_Layout.cshtml"; 3 }
提示:如果我們不想讓一個視圖使用_ViewStart.cshtml文件中指定的布局頁,我們可以在這個視圖文件的最上面添加@{ Layout = null; }。
1.5 小節
在這一章中,我們僅僅對ASP.NET MVC和Entity Framework做了一個非常簡單的概覽,並展示了在本書中我們將會一直使用的創建項目的方式,並解釋了Web站點的基礎,包括控制器、視圖、ViewBag和路由。我們只所以在本章中做了簡單描述,是因為在本書的后續章節中我們會詳細解釋這些概念,並指導我們快速開發一個數據驅動的Web站點。我們可能已經注意到了,在本章中我們沒有涉及任何有關模型的知識,這是因為該部分知識是我們下一章的內容,在下一章我們將對我們的Baby Store站點添加一些產品和分類。