從資料庫動態載入網站選單

by vivid 13. 十二月 2017 03:18

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N171219001
出刊日期: 2017/12/13

在這篇文章中,將要介紹如何在ASP.NET Core MVC專案中,從資料庫動態載入選單項目,套用Bootstrap的樣式來顯示兩層的網站選單。

預設Visual Studio 2017的「ASP.NET Core Web Application」範本專案中,有包含Bootstrap套件與Entity Framework Core套件,可以省略一些套件安裝與設計的步驟,本文將從建立Menu模型開始,然後利用Entity Framework Core Code First建立資料庫結構,再利用Visual Studio Scaffold功能自動產生控制器與新增、刪除、修改、查詢資料表資料的程式碼與檢視,最後透過Entity Framework Core查詢出資料表中的選單資料,套用Bootstrap範本,將把預設範本網站的選單修改如下:

clip_image002

圖 1:二層式選單。

建立ASP.NET Core MVC專案

1. 啟動Visual Studio 2017開發環境,從Visual Studio開發工具「File」-「New」-「Project」項目,在「New Project」對話盒中,確認視窗上方.NET Framework的目標版本為「.NET Framework 4.6.1」或以上版本,選取左方「Installed」清單-「Templates」-「Visual C#」程式語言,從「.NET Core」分類中,選取「ASP.NET Core Web Application」。設定專案名稱為「MenuDemo」,設定專案存放路徑,然後按下「OK」鍵,請參考下圖所示:

clip_image004

圖 2:建立ASP.NET Core MVC專案。

2. 在「New ASP.NET Core Web Application」對話盒中,確認左上方的清單選取「.NET Core」,右上方的清單ASP.NET Core版本為「ASP.NET Core 2.0」,選取下方的「Web Application ( Model – View – Controller) 」樣版專案,清除勾選下方的「Enable Docker Support」核取方塊,確定右方的「Authentication」項目設定為「No Authentication」,然後按下「OK」按鈕建立專案,請參考下圖所示:

clip_image006

圖 3:建立Web Application ( Model – View – Controller) 」樣版專案。

3. 從「Solution Explorer」視窗 -「Models」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」項目,從「Add New Item」對話盒中,選取「Code」分類下的,Class項目,然後在下方將Name設定為「Menu」最後按下「Add」按鈕,請參考下圖所示:

clip_image008

圖 4:加入Menu模型。

4. 在「Menu」類別檔案之中,為「Menu」類別定義「MenuId」、「Title」、「Url」與「ParentMenuId」屬性:

namespace MenuDemo.Models
{
    public class Menu
    {
        public int MenuId { get; set; }
        public string Title { get; set; }
        public string Url { get; set; }
        public int ParentMenuId { get; set; }
    }
}

 

5. 從Visual Studio 2017開發工具 -「Solution Explorer」視窗 - 「MenuDemo專案」-「Controllers」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Scaffolded Item」或「Controller」項目,開啟「Add Scaffold」對話盒,請參考下圖所示:

clip_image010

圖 5:建立控制器。

6. 在「Add Scaffold」對話盒中選取「MVC Controller with views, using Entity Framework」項目,然後按下「Add 」按鈕,請參考下圖所示:

clip_image012

圖 6:「MVC Controller with views, using Entity Framework」項目。

7. 在「Add Controller」對話盒中,點選「Data context class」後方的「+」按鈕,建立新的Data Context,請參考下圖所示:

clip_image014

圖 7:建立新的Data Context。

8. 在「New Data Context」對話盒中,將名稱命為「MenuDemo.Models.MyDbContext」,然後按下「Add 」按鈕,請參考下圖所示:

clip_image016

圖 8:將名稱命為「MenuDemo.Models.MyDbContext」。

9. 回到「Add Controller」對話盒,將「Model class」設定為「Menu」類別,勾選下方的「Generate views」核取方塊,然後設定Controller名稱為「MenusController」,然後按下「Add」按鈕,請參考下圖所示:

clip_image018

圖 9:建立控制器。

Visual Studio 2017便會在「Views\Menus」資料夾下,新增檢視檔案,以及在「Controllers」資料夾下,新增控制器程式碼MenusController.cs。而「MyDbContext」程式碼則是放在Data資料夾下。

檢視工具產生的「Data\MyDbContext」類別程式碼,「MyDbContext」類別將包含一個屬性以透過Entity Framework Core存取資料庫中「Menus」資料表資料:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace MenuDemo.Models
{
    public class MyDbContext : DbContext
    {
        public MyDbContext (DbContextOptions<MyDbContext> options)
            : base(options)
        {
        }

        public DbSet<MenuDemo.Models.Menu> Menu { get; set; }
    }
}

 

另外會自動在「Startup.cs」檔案中「ConfigureServices」方法中加入以下程式碼,以新增服務:

public void ConfigureServices(IServiceCollection services)
      {
          services.AddMvc();

          services.AddDbContext<MyDbContext>(options =>
                  options.UseSqlServer(Configuration.GetConnectionString("MyDbContext")));
      }

專案中會自動加入一個「appsettings.json」檔案,儲存資料庫連接字串:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "MyDbContext": "Server=(localdb)\\mssqllocaldb;Database=MyDbContext-d9eb5ef4-3749-40f9-8e95-9c6f10f7c31e;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

10. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

11. 開啟「Package Manager Console」視窗,在「Solution Explorer」視窗選取專案名稱。從Visual Studio 2017開發工具「Tools」-「NuGet Package Manager」-「Package Manager Console」開啟「Package Manager Console」視窗,然後在提示字元中輸入add-migration指令:

add-migration initial

執行結果參考下圖所示:

clip_image020

圖 10:使用Code First。

接著Visual Studio會在專案中建立一個Migrations資料夾,包含一些C#檔案。其中有一個XXX_initial.cs檔案內容大約如下:

using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;

namespace MenuDemo.Migrations
{
    public partial class initial : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Menu",
                columns: table => new
                {
                    MenuId = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    ParentMenuId = table.Column<int>(type: "int", nullable: false),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Url = table.Column<string>(type: "nvarchar(max)", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Menu", x => x.MenuId);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Menu");
        }
    }
}

 

還有一個MyDbContextModelSnapshot檔案,程式參考如下:

// <auto-generated />
using MenuDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using System;

namespace MenuDemo.Migrations
{
    [DbContext(typeof(MyDbContext))]
    partial class MyDbContextModelSnapshot : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "2.0.0-rtm-26452")
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

            modelBuilder.Entity("MenuDemo.Models.Menu", b =>
                {
                    b.Property<int>("MenuId")
                        .ValueGeneratedOnAdd();

                    b.Property<int>("ParentMenuId");

                    b.Property<string>("Title");

                    b.Property<string>("Url");

                    b.HasKey("MenuId");

                    b.ToTable("Menu");
                });
#pragma warning restore 612, 618
        }
    }
}


12. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

13. 開啟「Package Manager Console」視窗,然後在提示字元中輸入指令,以更新資料庫:

update-database

得到的執行結果如下圖所示:

clip_image022

圖 11:更新資料庫。

預設資料庫會建立在「C:\Users\登入帳號」資料夾中。

14. 開啟「Server Explorer」視窗,在「Data Connections」項目上按滑鼠右鍵,從快捷選單之中選取「Add Connection」項目,請參考下圖所示:

clip_image024

圖 12:連結到資料庫。

15. 若出現「Choose Data Source」視窗,則選擇「Microsoft SQL Server」,然後按「Continue」按鈕,請參考下圖所示:

clip_image026

圖 13:選取SQL Server資料庫。

16. 在「Add Connection」視窗中,設以下屬性,然後按下「OK」按鈕,請參考下圖所示:

l 資料來源 (Data Source) :Microsoft SQL Server (SqlClient)。

l Server name欄位:輸入「(localdb)\mssqllocaldb」。

l Authentication:選取「Windows Authentication」。

l Select or enter a database name欄位:選擇「MyDbContext-XXX」資料庫。

clip_image028

圖 14:設定連接資訊。

17. 檢視新建立的資料表與欄位資訊,參考如下:

clip_image030

圖 15:檢視新建立的資料表與欄位資訊。

18. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

19. 按CTRL+F5執行網站首頁(請注意:以下埠號「51129」可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下URL:

http://localhost:51129/Menus/

執行結果參考如下,點選畫面中的「Create New」超連結,參考下表,新增幾筆資料到資料庫:

clip_image032

圖 16:新增資料。

新增資料的「Create」檢視執行結果請參考下圖所示:

clip_image034

圖 17:新增資料。

最終定義的選單項目如下,工具也會自動產生資料編輯、刪除的程式碼,你可以透過網頁來修改它們的資料,請參考下圖所示:

clip_image036

圖 18:新增選單項目。

20. 檢查資料庫結構描述資訊。展開「Server Explorer」視窗-「Data Connections」-「MyDbContext-XXX」資料庫 -「Tables」- 「Menu」資料表,在「Menu」資料表上按滑鼠右鍵,從快捷選單中選取「Show Table Data」顯示資料表所有資料,請參考下圖所示:

clip_image038

圖 19:查詢資料表資料。

參考下圖,為「Menu」資料表中的資料:

clip_image040

圖 20:「Menu」資料表中的資料。

設計ViewComponent

21. 從「Solution Explorer」視窗 - 專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「ViewComponents」。

22. 定義「MenuList」類別。從Visual Studio 2017開發工具 -「Solution Explorer」- 「MenuDemo專案」 -「ViewComponents」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」項目,開啟「Add New Item」對話盒,從右上方文字方塊輸入「Class」搜尋,選取「Class」,設定名稱為「MenuList」,然後按下「Add」按鈕,建立新類別。

clip_image042

圖 21:加入ViewComponent類別。

23. 修改「MenuList」類別中的程式碼,繼承「ViewComponent」類別, 然後將游標移動到「ViewComponent」字串上方,工具就會自動提示你引用命名空間:

clip_image044圖 22:引用命名空間。

24. 修改「MenuList.cs」檔案中的程式碼,先在檔案最上方引用命名空間:

using MenuDemo.Models;

using Microsoft.AspNetCore.Mvc;

using Microsoft.EntityFrameworkCore;

25. 在「MenuList」類別定義一個MyDbContext 型別變數以及建構函式,並在建構函式加入以下程式碼:

private readonly MyDbContext _context;
public MenuList(MyDbContext context)
{
    _context = context;
}

 

26. 在「MenuList」類別定義一個InvokeAsync()方法:

public async Task<IViewComponentResult> InvokeAsync()
{
    var menus = await _context.Menu.OrderBy(m => m.ParentMenuId).ToListAsync();
    return View(menus);
}

完整的「MenuList」類別程式碼如下:

using MenuDemo.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MenuDemo.ViewComponents
{
    public class MenuList : ViewComponent
    {
        private readonly MyDbContext _context;
        public MenuList(MyDbContext context)
        {
            _context = context;
        }
        public async Task<IViewComponentResult> InvokeAsync()
        {
            var menus = await _context.Menu.OrderBy(m => m.ParentMenuId).ToListAsync();
            return View(menus);
        }
    }
}


27. 選取Visual Studio 開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

28. 接下來步驟要在專案中建立以下資料夾結構,並在其中加入一個Default.cshtml檔案,步驟分解如下:

clip_image046

圖 23:建立ViewCimponent資料夾結構

29. 從Visual Studio 2017開發工具-「Solution Explorer」- 「MenuDemo專案」 -「Views」-「Shared」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」項目,設定名稱為「Components」。

30. 從「Views」-「Shared」-「Components」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」項目,設定名稱為「MenuList」。

31. 從「Views」-「Shared」-「Components」-「MenuList」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「View」項目,開啟「Add View」對話盒,在「Add View」對話盒中,設定:

§ View name:「Default」。

§ Template:「Empty (without model)」

§ 勾選「Create as a partial view」。

然後按下「Add」按鈕。Visual Studio 2017便會在「MenuList」資料夾下,新增一個「Default.cshtml」檔案。

clip_image048

圖 24:產生Default.cshtml檔案。

32. 在「Default.cshtml」檔案之中加入以下程式碼:

@using System.Linq
@using MenuDemo.Models
@model IEnumerable<Menu>

<nav class = "navbar navbar-default 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 = "Home" asp-action = "Index" class = "navbar-brand"> MenuDemo </a>
        </div>
        <div class = "navbar-collapse collapse">
            <ul class = "nav navbar-nav">
                @if (Model != null && Model.Count<Menu>() > 0)
                {
                    foreach (var item in Model.Where(a => a.ParentMenuId.Equals(0)))
                    {
                        var submenu = Model.Where(a => a.ParentMenuId.Equals(item.MenuId));
                        int count = submenu.Count();

                        if (count == 0)
                        {
                            <li>
                                <a href="@item.Url"> @item.Title </a>
                            </li>
                        }
                        else
                        {
                            <li class = "dropdown">
                                <a href = "#" class = "dropdown-toggle" data-toggle = "dropdown"
                                   role = "button"
                                   aria-haspopup = "true"
                                   aria-expanded = "false">
                                    @item.Title
                                    <span class = "caret"> </span>
                                    <ul class = "dropdown-menu">
                                        @foreach (var subitem in submenu)
                                        {
                                            <li>
                                                <a href = "@subitem.Url"> @subitem.Title </a>
                                            </li>
                                        }
                                    </ul>
                                </a>
                            </li>
                        }
                    }
                }
            </ul>

        </div>
    </div>
</nav>

33. 修改「Views」-「Shared」-「_Layout.cshtml」檢視,在</body>標籤中使用「@* ... *@」註解原來的<nav>標籤:

@*<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 = "Home" asp-action = "Index" class = "navbar-brand">MenuDemo</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>

</div>

</div>

</nav>*@

34. 修改「_Layout.cshtml」檢視,在原來的「<nav>」標籤加入以下程式碼:

@await Component.InvokeAsync("MenuList")

35. 選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。

36. 按CTRL+F5執行網站首頁(請注意:上列的埠號「53131」可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下URL:

http://localhost:53131/home/

執行結果參考如下:

clip_image050

圖 25:網站選單。

網頁寬度不夠大時,將自動調整版面,請參考下圖所示:

clip_image052

圖 26:版面自動調整。

Tags:

.NET Magazine國際中文電子雜誌 | ASP.NET Core MVC | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List