2017年5月31日 星期三

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

延續前一篇文章的專案,我們將學習加入 Model,並且於其背後使用 SQL資料庫。

我們將重新建立 Controller,並且一次搞定 Controller/View/Model + Entuty Framework + 資料庫。


建立一個 Model類別

首先,在專案的 Models資料夾上,按下滑鼠右鍵,
再選加入
再選類別


出現的選單,
只選 ASP.Net Core
和右邊選類別
名字輸入:movie.cs


產生的程式碼框架如下圖:

我們先填入下列內容:

namespace MvcMovie.Models
{
   
public class movie
    {
       
public int ID { get; set; }
       
public string Title { get; set; }
       
public DateTime ReleaseDate { get; set; }
       
public string Genre { get; set; }
       
public decimal Price { get; set; }
    }
}



建立一個含 EF 的 Controller
在專案的 Controller資料夾上,按下滑鼠右鍵,
再選加入
再選控制器 (與前一篇文章不同,不是新增項目喔)


出現選單
再選控制器
右邊選使用 Entity Framework 執行檢視的控制器


會出現新增控制器的交談視窗
模型類別,按下拉式選單,選 movie (mvcMovie.Models)
資料內容類別,按下"+"的符號

然後按下新增

對於檢視部分,就保持預設的三個選項,都打勾。
對於控制器名稱,就保持預設的 moviesController
再按下新增

就會自動生成控制器類別(哇~程式碼有153行),還有五個檢視頁面:


這就是VS2017會自動幫你架好一個基本的 CRUD (create, read, update, and delete) 網頁框架(架手腳 scaffolding. )  再來,我們要建立資料庫,將要使用 Entuty Framework 的 Migrations 功能,它讓我們定義資料模型(data model),然後依據資料模型產生資料庫,維護資料庫。

程式碼雖然已經繩成,但是因為我們還沒有架設資料庫,所以直接執行,並到這新網頁: http://localhost:1234/movies/
會看到錯誤訊息:


專案增加 EF 工具

在方案總管,於專案MvcMovie 的上面按右鍵
再選 編輯 MvcMovie.csproj.

檔案打開之後,檢查是否有下列兩行,在 <ItemGroup>標籤之中:
<ItemGroup>
 
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
</ItemGroup>

註:如果按照微軟英文教學做,到了這裡要自己加入。但是因為我們一開始就已經選擇了個人驗證機制,所以此處已經有了這兩行。

此時,我們專案中有關 movies的相關檔案資料夾如下:

 

使用 EF 工具建立資料庫

建立資料庫,我們打開 comand prompt, 並且移到專案的目錄(含有Startup.cs檔案之處)
如果你也跟我一樣,有安裝 Power commands for Visual Studio,那麼在方案總管,
就可以直接點選進入!!

 
然後直下面的命令:
 

dotnet restore
dotnet ef migrations add Initial -c mvcMovieContext
dotnet ef database update -c mvcMovieContext

下面是這三個步驟的執行結果截圖
  • 執行 >dotnet restore

dotnet (.NET Core) 是跨平台的.NET工具. 微軟的說明文件在 這裡.
dotnet restore: 會依據 xxx .csproj 檔案裡面寫的定義,下載所使用的 NuGet 套件


  • 執行 >dotnet ef migrations add Initial -c mvcMovieContext

這一步驟,是在執行 EF 的 migration 命令,使用 initial名字,產生一堆資料庫操作的類別程式碼, 所產生的檔案會在
/Migrations/<date-time>_Initial.cs 


  • 執行 >dotnet ef database update -c mvcMovieContext



然後上一次我們是讓網頁功能表的mvcMovie 連結到 MovieControl, 這次我們連結到 MoviesController. 打開 _Layout.cshtml檔案,修改這行:(原來的預設控制器指向 movie, 現在改為指向movies )

 <a asp-area="" asp-controller="Movies" asp-action="Index" class="navbar-brand">MvcMovie</a>


執行它 Ctrl+F5,
然後按功能表上的 mvcMovie 地方:


可以再按 Creat New :


試著輸入資料:


回到 mvcMovie 那頁,已經有了一筆資料:

 

相依性注入Dependency Injection

打開檔案 Startup.cs
並且觀察成員涵式
 
ConfigureServices:
當中一行淡藍色的碼,就是顯示 movie資料庫T被加入相依性注入的容器中. 


再檢查檔案: Controllers/MoviesController.cs 
並且觀察類別的建構子 constructor:
就是這個地方,連結了資料庫與控制器!


在檢視中使用模型內的資料

我們在之前的實作中,已知讓控制器傳資料給檢視的方法(利用 ViewDate)。那麼,如何讓模型裡的資料,也被檢視 view所存取? 微軟又提供了什麼ㄈ便設計環境?

答案是:我們可先定義模型物件,然後再檢視的地方引用整個物件,而且在VS2017當中,可以自動顯示物件裡面的成員,幫便編輯程式碼。

譬如我們看
 in the Controllers/MoviesController.cs file:
 generated Details action method

參數 id  會由網址傳遞過來,譬如:
  http://localhost:1234/movies/details/1  
那麼它的動作是:
  • 前半段網址,代表控制器是連結到 movies controller
  • 第二段網址,則是代表指向的 action method 為  details .
  • 最後 id= 1 
  • +
傳遞參數 id  也可以在網址URL寫:




再來,檢查檔案 Views/Movies/Details.cshtml 
最上方的 @Model 就是用來指定,所要連結的模型 model !!!


再看 MoviesController當中,有個 method = Index()


其對應的 View = Index.cshtml
@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
   
<a asp-action="Create">Create New</a>
</p>
<table class="table">
   
<thead>
       
<tr>
               
<th>
                    @Html.DisplayNameFor(model => model.Title)
               
</th>
               
<th>
                    @Html.DisplayNameFor(model => model.ReleaseDate)
               
</th>
               
<th>
                    @Html.DisplayNameFor(model => model.Genre)
               
</th>
               
<th>
                    @Html.DisplayNameFor(model => model.Price)
               
</th>
           
<th></th>
       
</tr>
   
</thead>
   
<tbody>
@foreach (var item in Model) {
       
<tr>
           
<td>
                @Html.DisplayFor(modelItem => item.Title)
           
</td>
           
<td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
           
</td>
           
<td>
                @Html.DisplayFor(modelItem => item.Genre)
           
</td>
           
<td>
                @Html.DisplayFor(modelItem => item.Price)
           
</td>
           
<td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>

           
</td>
       
</tr>
}
   
</tbody>
</table>


我們可以試著改變下圖的地方,可以看到VS2017會自動提示,有哪些籌元可選 

本機 SQL資料庫

這個範例,現在是連結本機的 SQL資料庫。至於是電腦裡面哪一個資料庫? 由一個  ConnectionString 指定,它是被定義在檔案:  appsettings.json 

打開這個檔案
我們可以看到有兩個 ConnectionString,
一個是代表我們的 Movie資料庫 (mvcMovieContext)

一個是代表基本帳號管理的 default connection資料庫


本機資料庫是輕量級的 SQL Server Express Database,再點腦裏面,就是一個副檔名為 *.mdf 的檔案,和一個同名但是附檔名為 .log, 兩個檔案組成。預設所建立的資料庫檔案,會在目錄:
C:/使用者/<user> 這個目錄裡面:



在 VS2017裡面,有工具可以看其內容:
檢視
SQL Server物件總管
尋找到資料庫,資料表..
dbo.movie上面按右鍵

檢視表設計工具

會出現視窗:


也可以檢視資料表的資料:
 



植入種子資料

在模型,增加一個類別 Seeddata 如下:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
public static class SeedData
    {
       
public static void Initialize(IServiceProvider serviceProvider)
       
{
           
using (var context = new mvcMovieContext(
                serviceProvider.GetRequiredService<DbContextOptions<mvcMovieContext>>()))
            {
               
// Look for any movies.
               
if (context.movie.Any())
                {
                   
return;   // DB has been seeded
                }

                context.movie.AddRange(
                    
new movie
                     {
                         Title =
"When Harry Met Sally",
                         ReleaseDate = DateTime.Parse(
"1989-1-11"),
                         Genre =
"Romantic Comedy",
                         Price =
7.99M
                     },

                    
new movie
                     {
                         Title =
"Ghostbusters ",
                         ReleaseDate = DateTime.Parse(
"1984-3-13"),
                         Genre =
"Comedy",
                         Price =
8.99M
                     },

                    
new movie
                     {
                         Title =
"Ghostbusters 2",
                         ReleaseDate = DateTime.Parse(
"1986-2-23"),
                         Genre =
"Comedy",
                         Price =
9.99M
                     },

                  
new movie
                   {
                       Title =
"Rio Bravo",
                       ReleaseDate = DateTime.Parse(
"1959-4-15"),
                       Genre =
"Western",
                       Price =
3.99M
                   }
                );
                context.SaveChanges();
            }
        }
    }



請注意, 程式碼裡面,名稱是有區分大小寫的,如果直接拷貝英文網站裡面的碼,由於 MvcMovieContext 不等於 mvcMovieContext ,所以編譯環境會找不到,會一直有紅色底線錯誤!!

重新建置(編譯)之後,執行時需要先刪除先前輸入的各筆資料,通通刪光之後,關掉瀏覽器,再一次執行 Ctrl+F5就可看到:


上面途中, ReleaseDate 顯示了日期和零點零分零秒的時間,較為難看;我們可以修改原始的movie.cs 變成如下的碼。請加上黃色底色的三行。

using System;using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;namespace MvcMovie.Models
{
   
public class movie
    {
       
public int ID { get; set; }
       
public string Title { get; set; }        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]

       
public DateTime ReleaseDate { get; set; }
       
public string Genre { get; set; }
       
public decimal Price { get; set; }
    }
}



在 VS2017中,環境還提供一格功能,就是可以去除沒有用的 Using
可以在程式碼中(譬如:movie.cs)任何空白處按右鍵:


執行移除並排序 Using之後變成:

建置後執行結果:

 

 

解說控制器與檢視的幾項聯繫

上述執行畫面,當我們鼠標停留在第四筆資料的 Edit的時候,
其實,會看見瀏覽器將要傳遞的網址


這個網址是由 Views/Movies/Index.cshtml 檔案所產生的,因為程式碼中有下列,
其中第一行是產生 Edit的網址

第二行是產生 Detail的網址
第三行是產生 Delete的網址

        <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
       
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
       
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>

在上述 Index畫面,瀏覽器裡選擇觀看原始檔時,將發現已經展開的 HTML:


這即是 ASP.Net Core MVC機制,在背後完成的工作。
以Edit為例子,
就是會跑到控制器為 movies,
Action method = Edit()
而且參數 id = 5


當我們仔細查看 moviesController.cs的程式,將會發現有兩個 Edit() !!
這是怎麼回事?
原來,
一個是當 HTTP Post的時候呼叫的,一個是 HTTP Get的時候呼叫的.
程式之中,是用方框刮起來的屬性來指定


因為預設屬性是 HTTP Get, 所以,一個省略屬性,第二個有寫[HttpPost]

另外,我們看到屬性  [ValidateAntiForgeryToken] 是做什麼用呢?它讓我們只寫上這一行屬性,就會自動引入程式碼來做輸入值得型別與值域的檢查,就像下面截圖:




延伸的微軟閱讀資料


沒有留言:

張貼留言

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

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