Razor Page入門 - 7

by vivid 2. 九月 2020 11:42

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N200922201
出刊日期: 2020/9/2

這篇文章將延續《Razor Page入門 - 6》一文的情境,介紹當在ASP.NET Core Razor Page網站應用程式中刪除資料的作業,當使用者決定要刪除一筆資料時,我們會導向刪除確認頁,讓使用者有機會可以反悔刪除資料的動作,或者是選擇將資料真正的刪除。此外,在多個Razor Page之間,如果有HTML標籤、Razor程式碼等需要共用,我們可以使用部分檢視(Partial view)來達成。

設計資料刪除功能

我們先來改寫範例,設計資料刪除功能。延續前面文章建立的範例方案,先修改「MyServices」服務專案「IBookRepository」介面的程式碼,在「IBookRepository」介面之中,新增一個「Delete」方法,這個方法將根據「id」參數的值,來決定要刪除的圖書資料,同時,這個方法將會回傳想要刪除的「Book」物件,參考以下範例程式碼:

MyServices\IBookRepository.cs

using MyModels;
using System;
using System.Collections.Generic;
using System.Text;

namespace MyServices {
  public interface IBookRepository {
    IEnumerable<Book> GetAllBooks();
    Book GetBook( int id );
    Book Update( Book editBook );
    Book Create( Book newBook );
    Book Delete( int id );
  }
}


接著我們在「MyServices」服務專案「BookRepository」類別中,實作「IBookRepository」介面的「Delete」方法,透過「Remove」方法移除集合中對應的資料,請參考以下程式碼:

MyServices\BookRepository.cs

using MyModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyServices {
  public class BookRepository : IBookRepository {
    private List<Book> _books = null;
    public BookRepository( ) {
      _books = new List<Book>() {
         new Book() {
           Id = 1 ,
           Title = " Essential Programming Language " ,
           Price = 250 ,
           PublishDate = new DateTime( 2019 ,1,2 ) ,
           InStock = true ,
           Description = "Essential Programming Language "  ,
          Category = Category.Computers
         },
         new Book() {
           Id = 2 ,
           Title = "Telling Arts" ,
           Price = 245 ,
           PublishDate = new DateTime( 2019 , 4 , 15 ) ,
           InStock = true ,
           Description = " Telling Arts "  ,
          Category = Category.Arts
         },
           new Book() {
           Id = 3 ,
           Title = "Marvel" ,
           Price = 150  ,
           PublishDate = new DateTime( 2019 , 2, 21 ) ,
           InStock = true ,
           Description = " Marvel "  ,
          Category = Category.Commics
         },
          new Book() {
           Id = 4 ,
           Title = "The Beauty of Cook" ,
           Price = 450 ,
           PublishDate = new DateTime( 2019 ,12,2 ) ,
           InStock = true ,
           Description = " The Beauty of Cook "  ,
           Category = Category.Cooking
         }
      };
    }

    public Book Delete( int id ) {
      Book book = _books.FirstOrDefault( b => b.Id == id );
      if ( book != null ) {
        _books.Remove( book );
      }
      return book;
    }
    public Book Create( Book newBook ) {
      newBook.Id = _books.Max( b => b.Id ) + 1;
      _books.Add( newBook );
      return newBook;
    }

 

    public IEnumerable<Book> GetAllBooks( ) {
      return _books;
    }

    public Book GetBook( int id ) {
      return _books.FirstOrDefault( b => b.Id == id );
    }

    public Book Update( Book editBook ) {
      Book book = _books.FirstOrDefault( b => b.Id == editBook.Id );
      if ( book != null ) {
        book.Title = editBook.Title;
        book.Price = editBook.Price;
        book.PublishDate = editBook.PublishDate;
        book.InStock = editBook.InStock;
        book.Description = editBook.Description;
        book.Category = editBook.Category;
      }
      return book;
    }
  }
}

 

「Delete」方法中會傳入「id」參數,此為欲刪除的資料之編號,在方法中先利用集合物件提供的「FirstOrDefault」方法搜尋集合中與「Id」屬性值相符的「Book」物件,若不為「null」表示此「Book」物件存在於集合中,接著便利用「Remove」方法將此物件從集合中移除。

建立Delete Razor Page

下一個步驟要建立「Delete」Razor Page ,提供一個確認刪除的頁面。在「MyRazorWeb」Razor Page網站專案加入「Delete」Razor Page。在「Solution Explorer」視窗,「MyRazorPage」專案 - 「Pages \ Books」資料夾項目上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Razor Page」項目,請參考下圖所示:

clip_image002

圖 1:加入「Razor Page」項目。

在「Add New Scaffolded Item」對話盒左方選取「Razor Pages」分類,然後選取「Razor Page」項目,按下「Add 」按鈕,請參考下圖所示:

clip_image004

圖 2:選取「Razor Page」項目。

在「Add Razor Page」對話盒中,設定Razor Page名稱為「Delete」,勾選下方「Generate PageModel class」以及「Use a layout page」項目;然後按下「Add 」按鈕,請參考下圖所示:

clip_image006

圖 3:「Add Razor Page」對話盒。

在Visual Studio工具產生的「Delete.cshtml.cs」Razor Page類別程式檔案加入以下程式碼:

MyRazorWeb\Pages\Books\ Delete.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using MyModels;
using MyServices;

namespace MyRazorWeb.Pages.Books {
  public class DeleteModel : PageModel {
    private readonly IBookRepository bookRepository;
    public DeleteModel( IBookRepository bookRepository ) {
      this.bookRepository = bookRepository;
    }
    [BindProperty]
    public Book Book { get; set; }
    public IActionResult OnGet( int id ) {
      Book = bookRepository.GetBook( id );
      if ( Book == null ) {
        return RedirectToPage( "/NotFound" );
      }
      return Page();
    }
    public IActionResult OnPost( ) {
      Book book = bookRepository.Delete( Book.Id );

      if ( book == null ) {
        return RedirectToPage( "/NotFound" );
      }

      return RedirectToPage( "List" );
    }
  }
}

首先在「DeleteModel」類別中,宣告一個「private」、「readonly」的「IBookRepository」型別變數,透過建構函式插入(DI),將取得的「bookRepository」物件儲存在私有、唯讀的「bookRepository」變數。「DeleteModel」類別中定義一個「Book」屬性,套用了[BindProperty] Attribute。「DeleteModel」類別中的「OnGet」方法將傳入「id」參數,取得要刪除的「Book」物件編號,再透過「IBookRepository」的「GetBook」方法取回要刪除的「Book」物件放到「Book」屬性中。若找不到要刪除的「Book」物件,則透過「RedirectToPage」方法導向「NotFound」頁面顯示錯誤訊息。

下一步修改「Delete.cshtml」檔案中的程式碼,加入以下程式碼:

MyRazorWeb\Pages\Books\ Delete.cshtml

@page
@model MyRazorWeb.Pages.Books.DeleteModel
@{
  ViewData[ "Title" ] = "Delete";
}

<h1> Delete </h1>

<h3> Are you sure you want to delete this? </h3>
<div>
  <h4> Book </h4>
  <hr />
  <dl class = "row">
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.Title )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.Title )
    </dd>
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.Price )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.Price )
    </dd>
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.PublishDate )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.PublishDate )
    </dd>
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.InStock )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.InStock )
    </dd>
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.Description )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.Description )
    </dd>
    <dt class = "col-sm-2">
      @Html.DisplayNameFor( model => model.Book.Category )
    </dt>
    <dd class = "col-sm-10">
      @Html.DisplayFor( model => model.Book.Category )
    </dd>
  </dl>

  <form method = "post">
    <input type="hidden" asp-for = "Book.Id" />
    <input type = "submit" value = "Delete" class = "btn btn-danger" /> |
    <a asp-page = "./List"> Back to List </a>
  </form>
</div>

 

上半段程式碼先利用HTML Helper顯示要刪除的「Book」物件資料,讓使用者檢視這筆資料是否就是想刪除的資料。下半段則利用<form>標籤送出要刪除的「Book」物件「Id」屬性值。「Book」物件「Id」屬性值放在隱藏的Input欄位之中。當使用者點選表單中「Submit」按鈕時,將送出HTTP POST請求,以執行「OnPost」方法進行真正的刪除作業。

再來,修改「List.cshtml」檔案中的程式碼,在每一筆資料的右方,加入一個「Delete」超連結,讓使用選擇想刪除的資料:

List.cshtml

@page
@model MyRazorWeb.ListModel
@{
    ViewData["Title"] = "List";
}

<h1> List </h1>


<table class = "table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].Id )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].Title )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].Price )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].PublishDate )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].InStock )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].Description )
            </th>
            <th>
                @Html.DisplayNameFor( model => ( (IList<MyModels.Book>) model.Books )[0].Category )
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach ( var item in Model.Books ) {
        <tr>
            <td>
                @Html.DisplayFor( modelItem => item.Id )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.Title )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.Price )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.PublishDate )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.InStock )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.Description )
            </td>
            <td>
                @Html.DisplayFor( modelItem => item.Category )
            </td>
            <td>
              <a asp-page = "./Details" asp-route-Id = "@item.Id"> Details </a> |
              <a asp-page = "./Edit" asp-route-Id = "@item.Id"> Edit </a> |
              <a asp-page = "./Delete" asp-route-Id = "@item.Id"> Delete </a>
            </td>
        </tr>
        }
    </tbody>
</table>

 

選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。在Visual Studio開發工具,按CTRL+F5執行網站「Books/List」Razor Page,執行結果參考如下,每一筆圖書資料的最後,都會有一個「Delete」 超連結,請參考下圖所示:

clip_image008

圖 4:刪除資料測試。

點選任一筆資料的「Delete」 超連結之後,就會看到如下的畫面:

clip_image010

圖 5:確認刪除資料。

若按下「Delete」按鈕,則將資料真正移除,並回到「List」頁面,請參考下圖所示:

clip_image012

圖 6:資料真正移除。

若直接在網址上輸入查詢字串,模擬要刪除不存在的「100」號資料:

https://localhost:44300/Books/Delete/?id=100

請參考下圖所示:

clip_image014

圖 7:模擬刪除不存在的資料。

接著便會看到錯誤訊息,請參考下圖所示:

clip_image016

圖 8:顯示找不到資料的錯誤訊息。

部分檢視(Partial view)

非ASP.NET Core MVC專屬,在多個Razor Page要共用Razor程式與HTML,也可以使用部分檢視(Partial view)。檢視我們的圖書範例,其中「Details」與「Delete」Razor Page都重複地顯示圖書的詳細資料,這個部分可以利用部分檢視(Partial view)來減少重複性。

在「MyRazorWeb」Razor Page網站專案加入部分頁面(Partial view),為了在多個Razor Page之中重複使用,一般會將部分頁面(Partial view)放在「專案根目錄 \ Pages \ Shared\」資料夾之中。在「Solution Explorer」視窗,「MyRazorPage」專案 - 「Pages \ Shared」資料夾項目上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」項目。

在「Add New Item」對話盒左方選取「Visual C#」分類,然後從清單中選取「Razor View - Empty」項目,將名稱設定為「_BookPartial.cshtml」,然後按下「Add 」按鈕,參考下圖所示:

clip_image018

圖 9:加入「Razor View - Empty」項目。

在「_BookPartial.cshtml」檔案中加入以下重複出現在「Details」與「Delete」Razor Page中的程式碼,並且在檔案上方使用「@model」關鍵字描述傳入部分檢視的型別:

_BookPartial.cshtml

@page
@model MyRazorWeb.Pages.Books.DeleteModel
@{
  ViewData[ "Title" ] = "Delete";
}

<h1> Delete </h1>

<h3> Are you sure you want to delete this? </h3>
<div>
  <h4> Book </h4>
  <hr />

  <partial name = "_BookPartial" model = "@Model.Book" />

  <form method = "post">
    <input type = "hidden" asp-for = "Book.Id" />
    <input type = "submit" value = "Delete" class = "btn btn-danger" /> |
    <a asp-page = "./List"> Back to List </a>
  </form>
</div>

 

接著修改「Delete.cshtml」檔案,刪除出現在「_BookPartial.cshtml」檔案中的內容,並加上<partial>關鍵字,同時傳入「Book」物件:

Delete.cshtml

@page
@model MyRazorWeb.Pages.Books.DeleteModel
@{
  ViewData[ "Title" ] = "Delete";
}

<h1> Delete </h1>

<h3> Are you sure you want to delete this? </h3>
<div>
  <h4> Book </h4>
  <hr />

  <partial name = "_BookPartial" model = "@Model.Book" />

  <form method = "post">
    <input type = "hidden" asp-for = "Book.Id" />
    <input type = "submit" value = "Delete" class = "btn btn-danger" /> |
    <a asp-page = "./List"> Back to List </a>
  </form>
</div>

同樣地,修改「Details.cshtml」檔案,刪除出現在「_BookPartial.cshtml」檔案中的內容,並加上<partial>關鍵字:

Details.cshtml

@page
@model MyRazorWeb.Pages.Books.DetailsModel
@{
    ViewData["Title"] = "Details";
}
  <div>
    <h1> Book Details </h1>
    <hr />
    <partial name = "_BookPartial" model = "@Model.Book"  />
  </div>
<div>
    <a asp-page = "./List"> Back to List </a>
</div>

 

選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。接著在Visual Studio開發工具,按CTRL+F5執行網站,點選「Books」連結,顯示圖書清單,選取任一筆圖書資料的「Details」或「Delete」連結,執行結果參考如下圖所示:

clip_image020

圖 10:選取圖書資料的「Details」連結。

舉例來說若點選其中一筆資料的「Details」連結,就會看到圖書詳細資訊,請參考下圖所示:

clip_image022

圖 11:圖書詳細資訊。

同樣地,以下是刪除資料的確認畫面:

clip_image024

圖 11:圖書詳細資訊。

這樣我們就完成重複使用Razor程式的動作了。

Tags:

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

新增評論




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






NET Magazine國際中文電子雜誌

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

月分類Month List