這篇翻譯並記錄其實作過程,也加一點點基本解釋,算是給初學者一個中文的快速入門教學
首先什麼是MVC?
MVC是一個軟體架構的設計樣式,ASP.NET MVC是微軟實作此架構的名詞。而MVC是由以下三個單字的第一個字母所組合而成的。
Model(模型)負責維護應用程序數據和商業邏輯。
View(檢視)是應用程序的用戶界面,顯示數據。
Controller(控制器)負責處理用戶的請求,並使用Model數據呈現適當的View。
一般有個非正式的設計口訣「Model要重、View要笨、Controller要輕」
有關Web應用程式的架構概念如圖:
Web應用程式先天就會被劃分Model、View和Controller三個部份:View通常是客戶端的瀏覽器依取得的HTML繪製畫面,Controller會位於Web伺服器,而與資料庫互動的部份則是Model;傳統桌面應用程式,MVC三個部份通常位於同一台電腦,或者是透過持續性網路連線進行互動。
然而,對於基於HTTP的Web應用程式來說,由於HTTP基於請求/回應(Request/Response)模型,沒有請求就不會有回應,因此無法實現MVC中Model主動通知View的流程,如果View想根據Model最新狀態來呈現畫面,基本作法之一是透過持續性地主動詢問(Poll)伺服端Model來達成。
開始第一個Web App 程式
在 VS2017 中新增一個專案(檔案>新增>專案),名稱欄位填入: mvcMovie按確定後,出現細部設定:
軟體版本選擇 在左上的夏拉是選單,選目前最新 ASP.Net Core 1.1
然後範本選擇 Web 應用程式
預設的驗證是無驗證,我們按變更驗證,
然後選擇個別使用者帳戶,
按確定回到前一畫面:
再按確定,即可產生專案。第一個出現的是[概觀」畫面,它包含多文件的連結。以後可以回來仔細閱讀。但是初學者先不要看,以免迷失~~
可以直接按F5執行!
或者按下「 IISˊExpress 」的按鍵。
這時等於程式在你的機器上執行 IIS Express 網頁伺服器,也會自動開啟你的瀏覽器,而 VS2017 則是執行除錯中的狀態,我把瀏覽器縮小,與 Visual Studio 一起抓圖:
請注意
若瀏覽器大小改變的時候,畫面都會跟著做適當的修正,選單也會變成下拉是選單!!
下面我抓軮個小窄的畫面, 顯示其已經變成下拉是選單。
以程式觀點來看MVC:
- Model 模型:表示應用程式資料的類別。模型類別使用驗證邏輯來執行該數據的業務規則。通常,模型對像在數據庫中檢索和存儲模型狀態。 在本教學中,Movie模型從數據庫中檢索電影資料,將其提供給檢視view或更新它。其更新的資料寫入SQL Server資料庫。
- View 檢視:檢視是顯示應用程序用戶界面(UI)的組件。通常此UI顯示模型數據。(它就是 HTML, CSS那些東西,只含少量程式)
- Controller 控制器:處理瀏覽器請求的類別。他們檢索返迴響應的模型數據和調用視圖模板。在MVC應用程序中,檢視View只顯示信息;控制器處理和響應用戶輸入和交互。例如,控制器處理路由數據和查詢字符串值,並將這些值傳遞給模型。該模型可能會使用這些值來查詢資料庫。例如,http:// localhost:1234 / Home / About具有Home(控制器)和About(在主控制器上調用的操作方法)的路由數據。 http:// localhost:1234 / Movies / Edit / 5是使用電影控制器編輯ID = 5的電影的請求。
加入Controller
在方案總管裡,mvcMovie專案之下,有個資料夾圖示的 Controllers,在那 Controllers 上面按右鍵,
選加入,
再選新增項目。(注意:不是最上面那個『控制器(T) 』選項喔~~)
然後,在跳出的視窗中,
左邊選 Web
右邊選 MVC控制器類別
下方的名字輸入 MovieController.cs (習慣上我們都保留後面 Control字眼,取的名字在前,例如: XxxxxControl.cs)
自動生成的程式碼如下:
它是一個OOP的類別,衍生自Controller 類別,我們說 MovieController是一個Controller類別。 (注意, 若是結尾多一個"1", ex: MovieController1.cs, 會失敗喔!!)
它還須很多加工,才能看到效果。所以,這裡我們修改一下程式,我們在 Movieontroller.cs 原始檔案中,先把成員方法涵式 Index() 註解掉。(以後再改回來...)
在VS中,是先滑鼠選取範圍,然後按 Ctrl+KC,就會變成如下的註解。
(變回來的方法:滑鼠選取範圍,然後按 Ctrl+KU)
再來,我們輸入下列兩個成員方法涵式,在那類別之中:
// GET: /Movie/
public string Index()
{
return "This is my default action...";
}
// GET: /Movie/Welcome/
public string Welcome()
{
return "This is the Welcome action method...";
}
完成的程式如下圖:
然後,即可執行它!!
按下 F5,
咦~~似乎一樣....
別急.......
此時
你的瀏覽器中的 URL會類似: http://localhost:58473/ (注意:數字不會一樣)
當你手動修改成
http://localhost:58473/Movie就會看到
當你手動修改成
http://localhost:58473/movie/welcome
就會看到
好了,我們簡單立即的完成可執行的修改,建立了最初步的信心^___^
Routing機制
這裡要說明的概念是:- 在 Controller類別(class)中,每一個成員方法函式(method)就是一個 HTTP的執行端點,,就是要執行的動作,我們也稱之為 controller的 Action method。
- 同一主機的不同的網址,即是所謂HTTP的執行端點,例如上述兩個都是連接到 localhost主機(且相同的 port),但是斜線之後的網址不同,即是對應到內部不同的成員方法涵式 。
這個機制我們叫做 Routing
Routing 機制在 startup.cs 程式中, 這程式有多重目的, 現在我們只介紹 Routing,
所以, 預設的網址比對 Pattern 是:
/[Controller]/[ActionName]/[Parameters]
Startup.cs 裡面, 是把 Pattern 的指定值也寫進去, 它指定:
- 預設的 controller 是 Home (HomeController)
- 預設的 Action 是 Index
- 預設的參數是 id,後面寫個問號,代表是可有可無的選項(optional)
所謂預設的, 是可以省略的意思;就是當沒有指定時,由此預設的處理。
所以,下面圖中三個網址, 都是同一個網頁內容。
下面舉例說明網址URL,與對應的程式內部物件/值:
URL | Controller | Action | Id |
---|---|---|---|
http://localhost:1234/home | HomeController | Index | null |
http://localhost:1234/Home/index/123 | HomeController | Index | 123 |
http://localhost:1234/home/about | HomeController | About | null |
http://localhost:1234/home/contact | HomeController | Contact | null |
http://localhost:1234/Movie | MovieController | Index | null |
http://localhost:1234/movie/welcome | MovieController | Welcome | unll |
讓我們再修改一下 Welcome 這個 Action method, 讓他可以傳遞兩個參數:name 和 numTimes,改成如下的code。(參數是從URL網址傳遞到 Controller的 Action method)
// GET: /HelloWorld/Welcome/
// Requires using System.Text.Encodings.Web;
public string Welcome(string name, int numTimes = 1){
return HtmlEncoder.Default.Encode($"Hello {name}, NumTimes is: {numTimes}");
}
您可能發現有紅色的底線,出現在 HtmlEncoder的下方,這是代表有 Library沒被引用到:
在 Visual Studio中,可以鼠標移到其上,按 Alt + Enter,出現說明;
再按一次 Enter就會自加入一行:
然後即可以正常建置和測試:
您可以在瀏覽器的網址列輸入:
http://localhost:1234/movie/welcome?name=Jacky&numtimes=4
即可看到:
增加個檢視 ( View )
有控制器 MovieController 之後,我們要增加一個對應的 View 。在方案總管裡,mvcMovie專案之下,有個資料夾圖示的 View,
在那 View上面按右鍵,
選加入,
再選新增資料夾。命名為 Movie。
在那 Movie上面按右鍵,
選加入,
再選新增項目。
選擇 MVC檢視頁面
名字就用 Index.cshtml
對於幾乎空白的 Index.cshtml
我們寫上如下的內容:
@{
ViewData["Title"] = "Index";
}<h2>Index</h2>
<p>Hello from our View Template!</p>
ViewData["Title"] = "Index";
}<h2>Index</h2>
<p>Hello from our View Template!</p>
有關的 MovieController, 裡面也使用原本的 Index 涵式。
也就是只簡單一個 return View();
執行結果,(輸入URL = http://localhost:xxxx/movie )
傳遞參數到 View
之前我們的welcome() action, 參數是從URL網址傳遞到 Controller。現在我們要再由 Controller 傳遞到檢視 View去,首先 Controller端程式修改如下:namespace MvcMovie.Controllers
{
public class HelloWorldController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Welcome(string name, int numTimes = 1)
{
ViewData["Message"] = "Hello " + name;
ViewData["NumTimes"] = numTimes;
return View();
}
}
}
其次,
在方案總管中,資料夾 View之下的 Movie子資料夾,再增加一個 welcome.cshtml,
並寫入如的碼:
@{
ViewData["Title"] = "Welcome";
}<h2>Welcome</h2>
<ul>
@for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
{
<li>@ViewData["Message"]</li>
}</ul>
存檔之後按 Ctrl+F5 執行(啟動但不偵錯),並且瀏覽器中輸入 URL:
http://localhost:xxxx/movie/Welcome?name=Rick&numtimes=4
資料從網址先傳到 controller 。然後 controller 打包資料進入
ViewData
,一個小量資料的容器物件,可以想成一個內定的(Key-Value)小字典,固定傳此物件給對應的 View 。然後 View 能夠依據傳入的資料展開 Html
檢視 View 與 Layout 檔案
在每一頁都會看到相同的功能表 (MvcMovie, Home, About),這是因為採用了相同的 Layout,所謂Layout, 是我們定義一個畫面的規劃,讓每一頁都有相同的框架,譬如:都是相同的功能表,都是相同的側邊....
VS2017有內定的檔案,負責此事:
- 專案/ Views/ Shared/ _Layout.cshtml ==>用 Html 定義了框架
- 專案/ Views/ _ViewStart.cshtml ==> 呼叫的起點,引用了 _Layout.cshtml
我們檢查:_ViewStart.cshtml
它的內容是
@{
Layout = "_Layout";
}
Layout = "_Layout";
}
顯而易見,
它只是簡單的呼叫 _Layout.cshtml
它只是簡單的呼叫 _Layout.cshtml
然後查看 _Layout.cshtml
它的內容是
它的內容是
@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Movie App</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
@Html.Raw(JavaScriptSnippet.FullScript)</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Movie" asp-action="Index" class="navbar-brand">MvcMovie</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Movie App</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
@Html.Raw(JavaScriptSnippet.FullScript)</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Movie" asp-action="Index" class="navbar-brand">MvcMovie</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
@await Html.PartialAsync("_LoginPartial")
</div>
</div>
</nav>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2017 - MvcMovie</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)</body>
</html>
</div>
</div>
</nav>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2017 - MvcMovie</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)</body>
</html>
這個內容有點長,我們先找找 @RenderBody(), 那就是每個頁面展開不同內容的地方!
上面有兩行淺黃色的地方
那是我們要試著修改的地方:
- 第一行,修改Title文字,改成 Movie App (或其他你喜愛的文字)
- 另一行,修改預定的asp-controll, 改為 Movie
執行的結果:雖然打開時還是專案自動生成的首頁(Home Controller 的 Index網頁),但是當按下功能表的 mvcMovie, 已經可以跳到 Movie conroller 的 index網頁了.而且瀏覽器中,此網頁的標題,也變成我們修改的文字了.
好,這篇我們已經會建立專案,了解 Controller, View 還有 Layout相關的基本知識,下次我們要看 Model。
其他參考閱讀資料:
沒有留言:
張貼留言