2017年5月29日 星期一

ASP.Net Core MVC (VS2017) 入門點 - (1-1)

有個很不錯的自學(英文的) ASP.Net MVC tutorial ,我在VS2017照做一次後,讓我建立了基本的知識。然後,我轉到較新的 ASP.Net Core MVC 微軟的教學(使用Visual Studio).

這篇翻譯並記錄其實作過程,也加一點點基本解釋,算是給初學者一個中文的快速入門教學



首先什麼是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),但是斜線之後的網址不同,即是對應到內部不同的成員方法涵式 。 
進一步說明此概念,要讓不同網址執行不同的程式,其實有個機制負責處理「判斷與分配」執行的Action Method,觀念如圖:

這個機制我們叫做 Routing

Routing 機制在 startup.cs 程式中, 這程式有多重目的, 現在我們只介紹 Routing,


所以, 預設的網址比對 Pattern 是:
/[Controller]/[ActionName]/[Parameters]
 Startup.cs 裡面, 是把 Pattern 的指定值也寫進去, 它指定:
  • 預設的 controller 是 Home (HomeController)
  • 預設的 Action 是 Index
  • 預設的參數是 id,後面寫個問號,代表是可有可無的選項(optional)

所謂預設的, 是可以省略的意思;就是當沒有指定時,由此預設的處理。
所以,下面圖中三個網址, 都是同一個網頁內容。


下面舉例說明網址URL,與對應的程式內部物件/值:

URLControllerActionId
http://localhost:1234/homeHomeControllerIndexnull
http://localhost:1234/Home/index/123HomeControllerIndex123
http://localhost:1234/home/aboutHomeControllerAboutnull
http://localhost:1234/home/contactHomeControllerContactnull
http://localhost:1234/MovieMovieControllerIndexnull
http://localhost:1234/movie/welcomeMovieControllerWelcomeunll
注意一下,網址其實是不分大小寫的,所以寫 Home 和寫 home 是一樣的.


讓我們再修改一下 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上面按右鍵,
加入
再選新增項目

左邊選擇 Web
選擇 MVC檢視頁面
名字就用 Index.cshtml


對於幾乎空白的 Index.cshtml
我們寫上如下的內容:
@{
    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.cshtml
然後查看 _Layout.cshtml
它的內容是
 
@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet<!DOCTYPE html>
<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>&copy; 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(), 那就是每個頁面展開不同內容的地方!
上面有兩行淺黃色的地方
那是我們要試著修改的地方:
  1. 第一行,修改Title文字,改成 Movie App (或其他你喜愛的文字)
  2. 另一行,修改預定的asp-controll, 改為 Movie

執行的結果:雖然打開時還是專案自動生成的首頁(Home Controller 的 Index網頁),但是當按下功能表的 mvcMovie, 已經可以跳到 Movie conroller 的 index網頁了.而且瀏覽器中,此網頁的標題,也變成我們修改的文字了.


好,這篇我們已經會建立專案,了解 Controller, View 還有 Layout相關的基本知識下次我們要看 Model。




其他參考閱讀資料:

沒有留言:

張貼留言

ASP.Net Core MVC (VS2017) 入門點 - (2-1)

再回來看看 Visual Studio幫你產生的使用者驗證管理, 就是我們 新增專案 時, 有個『 變更驗證 』選項,其下有四種選項,它會自動產生很多Code, 這裡研究清楚以便日後使用.