在 ASP.NET Core 應(yīng)用中更新生成的頁(yè)面

2019-04-17 08:57 更新

構(gòu)架的電影應(yīng)用有個(gè)不錯(cuò)的開(kāi)始,但是展示效果還不夠理想。 ReleaseDate 應(yīng)是 Release Date(兩個(gè)詞)。

在 Chrome 中打開(kāi)的電影應(yīng)用程序

更新生成的代碼

打開(kāi) Models/Movie.cs 文件,并添加以下代碼中突出顯示的行:

C#

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPagesMovie.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; }

        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
    }
}

[Column(TypeName = "decimal(18, 2)")] 數(shù)據(jù)注釋使 Entity Framework Core 可以將 Price 正確映射到數(shù)據(jù)庫(kù)中的貨幣。 有關(guān)詳細(xì)信息,請(qǐng)參閱數(shù)據(jù)類型

DataAnnotations 未包括在下一個(gè)教程中。 Display 特性指定要顯示的字段名稱的內(nèi)容(本例中應(yīng)為“Release Date”,而不是“ReleaseDate”)。 DataType 屬性指定數(shù)據(jù)的類型(日期),使字段中存儲(chǔ)的時(shí)間信息不會(huì)顯示。

瀏覽到 Pages/Movies,并將鼠標(biāo)懸停在“編輯”鏈接上以查看目標(biāo) URL。

鼠標(biāo)懸停在“編輯”鏈接上的瀏覽器窗口,顯示了 http://localhost:1234/Movies/Edit/5 的鏈接 URL

“編輯”、“詳細(xì)信息”和“刪除”鏈接是在 Pages/Movies/Index.cshtml 文件中由定位標(biāo)記幫助程序生成的。

CSHTML

@foreach (var item in Model.Movie) {
        <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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

標(biāo)記幫助程序使服務(wù)器端代碼可以在 Razor 文件中參與創(chuàng)建和呈現(xiàn) HTML 元素。 在前面的代碼中,AnchorTagHelper 從 Razor 頁(yè)面(路由是相對(duì)的)、asp-page 和路由 ID (asp-route-id) 動(dòng)態(tài)生成 HTML href 特性值。 有關(guān)詳細(xì)信息,請(qǐng)參閱頁(yè)面的 URL 生成

在最喜歡的瀏覽器中使用“查看源”來(lái)檢查生成的標(biāo)記。 生成的 HTML 的一部分如下所示:

HTML

<td>
  <a href="/Movies/Edit?id=1">Edit</a> |
  <a href="/Movies/Details?id=1">Details</a> |
  <a href="/Movies/Delete?id=1">Delete</a>
</td>

動(dòng)態(tài)生成的鏈接通過(guò)查詢字符串傳遞電影 ID(例如,https://localhost:5001/Movies/Details?id=1 中的 ?id=1)。

更新“編輯”、“詳細(xì)信息”和“刪除”Razor 頁(yè)面以使用“{id:int?}”路由模板。 將上述每個(gè)頁(yè)面的頁(yè)面指令從 @page 更改為 @page "{id:int}"。 運(yùn)行應(yīng)用,然后查看源。 生成的 HTML 會(huì)將 ID 添加到 URL 的路徑部分:

HTML

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

如果對(duì)具有“{id: int}” 路由模板的頁(yè)面進(jìn)行的請(qǐng)求中不包含整數(shù),則將返回 HTTP 404(未找到)錯(cuò)誤。 例如,http://localhost:5000/Movies/Details 將返回 404 錯(cuò)誤。 若要使 ID 可選,請(qǐng)將 ? 追加到路由約束:

CSHTML

@page "{id:int?}"

若要測(cè)試 @page "{id:int?}" 的行為:

  • 在 Pages/Movies/Details.cshtml 中將 page 指令設(shè)置為 @page "{id:int?}"。
  • 在 public async Task<IActionResult> OnGetAsync(int? id) 中(位于 Pages/Movies/Details.cshtml.cs 中)設(shè)置斷點(diǎn)。
  • 導(dǎo)航到 https://localhost:5001/Movies/Details/。

使用 @page "{id:int}" 指令時(shí),永遠(yuǎn)不會(huì)命中斷點(diǎn)。 路由引擎返回 HTTP 404。 使用 @page "{id:int?}" 時(shí),OnGetAsync 方法返回 NotFound (HTTP 404)。

盡管不建議這樣做,但仍可以將 OnGetAsync 方法(在 Pages/Movies/Delete.cshtml.cs 中)編寫(xiě)為:

C#

public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        Movie = await _context.Movie.FirstOrDefaultAsync();
    }
    else
    {
        Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
    }

    if (Movie == null)
    {
        return NotFound();
    }
    return Page();
}

測(cè)試上述代碼:

  • 選擇刪除鏈接。
  • 從 URL 中刪除 ID。 例如,將 https://localhost:5001/Movies/Delete/8 更改為 https://localhost:5001/Movies/Delete。
  • 在調(diào)試程序中逐步執(zhí)行代碼。

查看并發(fā)異常處理

查看 Pages/Movies/Edit.cshtml.cs 文件中的 OnPostAsync 方法:

C#


public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Attach(Movie).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!MovieExists(Movie.ID))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return RedirectToPage("./Index");
}

private bool MovieExists(int id)
{
    return _context.Movie.Any(e => e.ID == id);
}

當(dāng)一個(gè)客戶端刪除電影并且另一個(gè)客戶端對(duì)電影發(fā)布更改時(shí),前面的代碼會(huì)檢測(cè)并發(fā)異常。

測(cè)試 catch 塊:

  • 在 catch (DbUpdateConcurrencyException)上設(shè)置斷點(diǎn)
  • 對(duì)電影選擇“編輯”,進(jìn)行更改,但不要輸入“保存”。
  • 在其他瀏覽器窗口中,選擇同一電影的“刪除”鏈接,然后刪除此電影。
  • 在之前的瀏覽器窗口中,將更改發(fā)布到電影。

生產(chǎn)代碼可能要檢測(cè)并發(fā)沖突。 有關(guān)詳細(xì)信息,請(qǐng)參閱處理并發(fā)沖突

發(fā)布和綁定審閱

檢查 Pages/Movies/Edit.cshtml.cs 文件:

C#

public class EditModel : PageModel
{
    private readonly RazorPagesMovieContext _context;

    public EditModel(RazorPagesMovieContext context)
    {
        _context = context;
    }

    [BindProperty]
    public Movie Movie { get; set; }

    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        Movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);

        if (Movie == null)
        {
            return NotFound();
        }
        return Page();
    }
    
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Attach(Movie).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!_context.Movie.Any(e => e.ID == Movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return RedirectToPage("./Index");
    }
}

當(dāng)對(duì) Movies/Edit 頁(yè)面進(jìn)行 HTTP GET 請(qǐng)求時(shí)(例如 http://localhost:5000/Movies/Edit/2):

  • OnGetAsync 方法從數(shù)據(jù)庫(kù)提取電影并返回 Page 方法。
  • Page 方法呈現(xiàn)“Pages/Movies/Edit.cshtml”Razor 頁(yè)面。 Pages/Movies/Edit.cshtml 文件包含模型指令 (@model RazorPagesMovie.Pages.Movies.EditModel),這使電影模型在頁(yè)面上可用。
  • “編輯”表單中會(huì)顯示電影的值。

當(dāng)發(fā)布 Movies/Edit 頁(yè)面時(shí):

  • 此頁(yè)面上的表單值將綁定到 Movie 屬性。 [BindProperty] 特性會(huì)啟用模型綁定。C#復(fù)制[BindProperty] public Movie Movie { get; set; }
  • 如果模型狀態(tài)中存在錯(cuò)誤(例如,ReleaseDate 無(wú)法被轉(zhuǎn)換為日期),則會(huì)使用已提交的值顯示表單。
  • 如果沒(méi)有模型錯(cuò)誤,則電影已保存。

“索引”、“創(chuàng)建”和“刪除”Razor 頁(yè)面中的 HTTP GET 方法遵循一個(gè)類似的模式。 “創(chuàng)建”Razor 頁(yè)面中的 HTTP POST OnPostAsync 方法遵循的模式類似于“編輯”Razor 頁(yè)面中的 OnPostAsync 方法所遵循的模式。

在下一教程中將添加搜索。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)