檢視元件

by vivid 5. 九月 2018 03:56

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N180919901
出刊日期: 2018/09/05

檢視元件(View components)是可在檢視中重複使用的程式,在這篇文章中,將要介紹如何在ASP.NET Core MVC專案之中設計檢視元件(View components),並利用Entity Framework Core取得資料庫的資料來顯示。

 

什麼是檢視元件(View components)

MVC前版使用子動作(Child Action)來建立可重複使用的元件,但ASP.NET Core沒有Child Action,取而代之新增一個檢視元件(View components),它類似部分檢視(Partial View),但功能更為強大,更易擴充,通常在有複雜的商業邏輯,不易使用部分檢視(Partial View)來實作時,便可以使用檢視元件(View components),很適合用來撰寫動態導覽選單、標籤雲(Tag Cloud)、購物車清單等等程式。

本文將沿用本站「設計ASP.NET Core MVC應用程式」一文建立的資料庫來進行設計。讓檢視元件(View components)利用Entity Framework Core叫用資料庫預存程序取回滿足篩選條件的員工清單資料。

Entity Framework Core提供「DbSet<T>.FromSql()」與「DbContext.Database.ExecuteSqlCommand()」兩個方法來叫用預存程序。為了讓Entity Framework Core能夠叫用預存程序,撰寫預存程序時需要注意以下事項:

  • 回傳的結果必需是Entity型別,也就是說預存程序必需將Entity對應的資料表之所有欄位資料回傳。
  • 回傳的結果不可包含相關聯的資料表資料,不可以使用join語法。

首先我們先利用Entity Framework Core 移轉(Migration)來建立預存程序,開啟「Package Manager Console」視窗,在「Solution Explorer」視窗選取專案名稱。從Visual Studio 2017開發工具「Tools」-「NuGet Package Manager」-「Package Manager Console」開啟「Package Manager Console」視窗,然後在提示字元中輸入「add-migration」指令:

Add-Migration usp_GetEmployees

執行結果參考下圖所示:

clip_image002

圖 1:利用Entity Framework Core 移轉(Migration)來建立預存程序。

接著Visual Studio會在專案「Migrations」資料夾,產生一個C#檔案,類別中包含「Up」與「Down」兩個方法,修改方法程式碼如下,「Up」方法加入建立預存程序邏輯;「Down」方法則加入刪除預存程序邏輯:

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

namespace EFCDemo.Migrations {
  public partial class usp_GetEmployees : Migration {
    protected override void Up( MigrationBuilder migrationBuilder ) {
      var usp =
$@"
CREATE PROCEDURE [dbo].GetEmployees
    @key varchar(50)
AS
    SELECT Id, Name, Height, Married from Employees
    where Name like @key + '%'
";
      migrationBuilder.Sql( usp );
    }

    protected override void Down( MigrationBuilder migrationBuilder ) {
      var cmd =
$@"
DROP PROCEDURE [dbo].GetEmployees;
GO
";
      migrationBuilder.Sql( cmd );
    }
  }
}

 

選取Visual Studio 開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。在「Package Manager Console」視窗,命令提示字元中輸入指令,以更新資料庫:

Update-Database

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

clip_image004

圖 2:更新結構描述資訊。

開啟Visual Studio開發工具「Server Explorer」視窗,檢視新建立的「GetEmployees」預存程序資訊,請參考下圖所示:

clip_image006

圖 3:檢視新建立的「GetEmployees」預存程序資訊。

建立控制器

從「Solution Explorer」視窗,專案的「Controllers」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「Controller」項目,然後在「Add Scaffold」對話盒中選取「MVC」-「Controller」分類下的「MVC Controller - Empty」項目,按下「Add 」按鈕,設定控制器名稱為「HomeController」;然後按下「Add 」按鈕,請參考下圖所示:

clip_image008

圖 4:建立「HomeController」控制器。

在「HomeController」控制器加入一個「GetAllEmployees」方法,利用「DbSet<T>.FromSql()」方法來執行預存程序:

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

namespace EFCDemo.Controllers {
  public class HomeController : Controller {
    private readonly MyDbContext _context;
    public HomeController( MyDbContext context ) {
      _context = context;
    }
    public IActionResult Index( ) {
      return View( );
    }
    public string GetAllEmployees( ) {
      var param = "M";
      var sql = $"GetEmployees '{param}'";
      var list = _context.Employees.FromSql( sql );
      var count = list.Count( ).ToString( );
      return count;
    }
  }
}

 

選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。在Visual Studio開發工具,按CTRL+F5執行網站首頁,此時會啟動瀏覽器,以及開發用的IIS Express伺服器,自動指定一個埠號(port)來執行網站應用程式。(請注意:埠號可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下網址(URL):

http://localhost:53083/Home/GetAllEmployees

執行結果參考如下:

clip_image010

圖 5:測試叫用預存程序。

設計檢視元件類別(View Component Class)

檢視元件(View Components)包含兩部份,一個類別(class),以及它回傳的結果(通常是View)。類別可以繼承ViewCompoment,也可以是可以是POCO類別,在類別上方套用「ViewComponent」attribute。繼承ViewComponent類別可擁有基本的屬性與法方法, 較易進行設計。

讓我們來建立一個檢視元件類別,此類別可以放在專案中任意資料夾。從「Solution Explorer」視窗 - 專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「ViewComponents」。

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

clip_image012

圖 6:建立檢視元件類別(View Component Class)。

修改「EmployeeList」類別的程式碼,先在檔案最上方引用命名空間,修改「EmployeeList」類別中的程式碼,繼承「ViewComponent」類別,並定義一個InvokeAsync()方法:

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

namespace EFCDemo.ViewComponents {
  public class EmployeeList : ViewComponent {
    private readonly MyDbContext _context;
    public EmployeeList( MyDbContext context ) {
      _context = context;
    }
    public async Task<IViewComponentResult> InvokeAsync( ) {
      var param = "M";
      var sql = $"GetEmployees '{param}'";
      var list = await _context.Employees.FromSql( sql ).ToListAsync();
      return View( list );
    }
  }
}


檢視元件類別(View Component Class)完全支援建構函式相依性插入(constructor dependency injection),因此範例中透過DI直接取得存取資料庫的「MyDbContext」實體。檢視元件(View Component)在InvokeAsync 方法定義處理邏輯,此方法將回傳「IViewComponentResult」實例。

我們叫用「FromSql」方法來執行預存程序取得查詢結果,然後呼叫View()方法,將查詢結果傳到檢視。

設計檢視元件檢視(View Component View)

一個檢視元件的檢視預設的名稱為「Default」,執行時期(Runtime)會搜尋以下路徑來找尋檢視:

  • Views/控制器名稱/Components/檢視元件名稱/檢視名稱
  • Views/Shared/Components/檢視元件名稱/檢視名稱

接著我們就根據以下的資料夾結構來建立「Default.cshtml」檔案,請參考下圖所示:

clip_image014

圖 7:建立檢視元件檢視(View Component View)。

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

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

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

  • View name:「Default」。
  • Template:「Empty (without model)」
  • 勾選「Create as a partial view」,並清除勾選其它所有核取方塊。

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

clip_image016

圖 8:加入檢視元件檢視(View Component View)。

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

@model IEnumerable<EFCDemo.Models.Employee>

@{
  Layout = null;
}
<table style = "border : 1px solid blue">
  <thead>
    <tr>
      <th>
        @Html.DisplayNameFor( model => model.Id )
      </th>
      <th>
        @Html.DisplayNameFor( model => model.Name )
      </th>
      <th>
        @Html.DisplayNameFor( model => model.Height )
      </th>
      <th>
        @Html.DisplayNameFor( model => model.Married )
      </th>

    </tr>
  </thead>
  <tbody>
    @foreach ( var item in Model ) {
      <tr>
        <td>
          @Html.DisplayFor( modelItem => item.Id )
        </td>
        <td>
          @Html.DisplayFor( modelItem => item.Name )
        </td>
        <td>
          @Html.DisplayFor( modelItem => item.Height )
        </td>
        <td>
          @Html.DisplayFor( modelItem => item.Married )
        </td>
      </tr>
    }
  </tbody>
</table>

 

使用檢視元件

建立「Home\Index」檢視。將游標停留在「HomeController」制器程式設計畫面「Index」方法之中,按滑鼠右鍵,從快捷選單選取「Add View」,12. 在「Add MVC View」對話盒中,設定以下項目:

  • View name:「Index」。
  • Template:「Empty (without model)」。
  • Model class:不設定。
  • 清除勾選所有核取方塊。

然後按下「Add」按鈕。Visual Studio 2017便會在「Views\Home」資料夾下,新增一個「Index.cshtml」檔案,修改「Views\Home\Index」檢視,在</body>標籤之上,加入以下程式碼:

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name = "viewport" content = "width=device-width" />
  <title> Index </title>
</head>
<body>
  @await Component.InvokeAsync( "EmployeeList"  )
</body>
</html>

 

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

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

http://localhost:埠號/home/

執行結果參考如下:

clip_image018

圖 9:測試使用檢視元件。

結束執行程式,回到Visual Studio 開發工具程式編輯畫面。

傳入參數

前文範例寫死了要傳遞到預存程序的參數資訊,現在讓我們為檢視元件(View Component)加上參數資訊,修改檢視元件(View Component)「InvokeAsync」方法,加入一個字串型別的「param」參數,並將參數傳遞到「FromSql」方法:

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

namespace EFCDemo.ViewComponents {
  public class EmployeeList : ViewComponent {
    private readonly MyDbContext _context;
    public EmployeeList( MyDbContext context ) {
      _context = context;
    }
    public async Task<IViewComponentResult> InvokeAsync( string param ) {
      //var param = "M";
      var sql = $"GetEmployees '{param}'";
      var list = await _context.Employees.FromSql( sql ).ToListAsync();
      return View( list );
    }
  }
}

 

檢視元件(View Component)不透過模型繫結(Model Binding),參數直接來自於「Component.InvokeAsync」呼叫時傳的參數。修改「Home\Index」檢視中的程式碼如下:

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name = "viewport" content = "width=device-width" />
  <title>Index</title>
</head>
<body>
  @await Component.InvokeAsync( "EmployeeList" , "M" )
</body>
</html>

 

將檢視元件當作標籤協助程式

ASP.NET Core 1.1及以上版本,可以直接將檢視元件(View Component)當作標籤協助程式(Tag Helper)來使用。

在「Views」資料夾加入一個「_ViewImports.cshtml」檔案。從Visual Studio 開發工具「Solution Explorer」視窗 -「Views」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」選項,從「Add New Item」對話盒中,選取「Web」分類中的「Razor View Imports」,檔案名稱設定為「_ViewImports.cshtml」,然後按下「Add」按鈕,請參考下圖所示:

clip_image020

圖 10:加入「_ViewImports.cshtml」檔案。

修改「_ViewImports.cshtml」檔案,在其中加入以下程式碼,註冊標籤協助程式,其中的「EFCDemo」是標籤協助程式(檢視元件)所在的組件名稱,預設就是專案的名稱:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@addTagHelper *, EFCDemo

修改「Home\Index」檢視程式碼如下,你需要將使用「Pascal」命名法的標籤協助程式,改成全部小寫的「Kebab」命名法,每個字之間使用「-」符號區隔:

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name = "viewport" content = "width=device-width" />
  <title> Index </title>
</head>
<body>

  <vc:employee-list param="M">

  </vc:employee-list>
</body>
</html>


 

在控制器叫用檢視元件

最後,若想要在控制器叫用檢視元件,只要直接叫用控制器「ViewComponent」方法,傳入檢視元件(ViewComponent)名稱與參數資訊即可:

public IActionResult GetEmployeeList( ) {
  return ViewComponent( "EmployeeList" , "C" );
}

Tags:

.NET Core | .NET Magazine國際中文電子雜誌 | ASP.NET Core MVC

新增評論




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






NET Magazine國際中文電子雜誌

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

月分類Month List