尝试为 ASP .NET Core razor 页面编写 CRUD 函数。为什么我的删除功能不起作用?

Trying to write CRUD fucntions for ASP .NET Core razor pages. Why doesn't my delete function work?

GitHub

Delete.cshtml.cs

#region snippet_All
using Project.Models; //using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;

namespace Project.Pages.Albums //ContosoUniversity.Pages.Students
{
    public class DeleteModel : PageModel
    {
        private readonly Chinook _context;

        public DeleteModel(Chinook context)
        {
            _context = context;
        }

        [BindProperty]
        public Album Album { get; set; }
        public string ErrorMessage { get; set; }

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

            Album = await _context.Albums
                .AsNoTracking()
                .FirstOrDefaultAsync(m => m.AlbumId == id);

            if (Album == null)
            {
                return NotFound();
            }

            if (saveChangesError.GetValueOrDefault())
            {
                ErrorMessage = "Delete failed. Try again";
            }

            return Page();
        }

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

            var album = await _context.Albums.FindAsync(id);

            if (album == null)
            {
                return NotFound();
            }

            try
            {
                _context.Albums.Remove(album);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            catch (DbUpdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log.)
                return RedirectToAction("./Delete",
                                     new { id, saveChangesError = true });
            }
        }
    }
}
#endregion

Delete.cshtml

@page
@model Project.Pages.Albums.DeleteModel

@{
    ViewData["Title"] = "Delete";
}

<h1>Delete</h1>

<p class="text-danger">@Model.ErrorMessage</p>

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

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

Album.cshtml

@page
@model Project.Pages.AlbumsModel            
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<div class="row">
    <h1 class="display-2">Albums</h1>
    <table class="table">
        <thead class="thead-inverse">
            <tr>
                <th>Album ID, artist ID, Album title</th>
            </tr>
        </thead>
        <tbody>
            @foreach (string album in Model.Albums)
            {
                <tr>
                    <td>@album</td>
                    <td><a asp-page="./Delete" asp-route-id="@album">Delete</a></td>
                </tr>
            }
        </tbody>
    </table>
</div>
<div class="row">
    <p>Enter a title & ArtistID for a new album:&nbsp;</p>
    <form method="POST">
        <div><input asp-for="Album.Title" /></div>
        <div><input asp-for="Album.ArtistId" /></div>
        <input type="submit" />
    </form>
        @* <p>Enter a value and Album ID for a new album title:&nbsp;</p>
    <form method="POST">
        <div><input asp-for="Album.Title" /></div>
        <div><input asp-for="Album.AlbumId" /></div>
        <input type="submit" />
    </form> *@
</div>

Album.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using System;

namespace Project.Pages
{
    public class AlbumsModel : PageModel
    {
        private Chinook db;

        public AlbumsModel(Chinook injectedContext)
        {
            db = injectedContext;
        }
        public IEnumerable<string> Albums { get; set; }
        public void OnGet()
        {
            ViewData["Title"] = "Chinook Web Site - Albums";
            // Albums = db.Albums.Select(s => s.Title);
            Albums = db.Albums.Select(s => s.AlbumId.ToString() + ". " + s.ArtistId + ". " + s.Title);
        }
        [BindProperty]
        public Album Album { get; set; }

        public IActionResult OnPost()
        {
            if (ModelState.IsValid)
            {
                db.Albums.Add(Album);
                db.SaveChanges();
                return RedirectToPage("/albums");
            }
            return Page();
        }

        // void RemoveAlbum(int albumId)
        // {
        //     var album = db.Albums.Find(albumId);
        //     if (album == null)
        //         throw new ArgumentOutOfRangeException();
        //     db.Albums.Remove(album);
        //     db.SaveChanges();
        // }

        public IActionResult DeleteAlbum(int AlbumId)
        {
            var album = db.Albums.Find(AlbumId);

            if (album == null) return Page();

            db.Albums.Remove(album); db.SaveChanges(); return RedirectToPage("/albums");
        }
    }
}

我的项目构建并运行良好,但删除按钮只刷新页面。我试过重新加载页面,但这没有任何可能性。我不相信 <td><a asp-page="./Delete" asp-route-id="@album">Delete</a></td> 是正确的,但是当我尝试将 AlbumId 插入其中而不仅仅是 album 时,我总是会出错。有什么帮助吗? TIA.

根据您的代码和描述,看起来在Album.cshtml页面中,您将列出相册,如果单击“删除”超链接,它将重定向到Delete.cshtml页面并显示所选相册,之后,单击“删除”按钮删除该项目并重定向到索引页面。如果是这种情况,请参考以下步骤修改您的代码。

首先,在 Album.cshtml 页面中:

由于 Delete.cshtml 页面位于“相册”文件夹中,因此当您添加超链接(<a> 标记)时,asp-page 属性应如下所示:asp-page="/Albums/Delete".

<a> 标签如下:<a asp-page="/Albums/Delete" asp-route-id="@album">Delete</a>.

其次,在Delete.cshtml.cs文件中:

如果查看Album.cshtml.cs文件或者使用F12开发者工具查看参数,可以看到id是一个字符串值,而不是int类型。因此,更改代码如下:

    public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false)
    {

        if (id == null)
        {
            return NotFound();
        }
        //using string.split method to split the id parameter, and get the albumid.
        var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);

        Album = await _context.Albums
            .AsNoTracking()
            .FirstOrDefaultAsync(m => m.AlbumId == albumid);

        if (Album == null)
        {
            return NotFound();
        }

        if (saveChangesError.GetValueOrDefault())
        {
            ErrorMessage = "Delete failed. Try again";
        }

        return Page();
    }

并且在Delete.cshtml页面中,您还应该在页面头部添加tag helper reference,并使用asp-route-id属性将albumid传递给Post方法,代码如下:

@page  "{id?}"
@model Project.Pages.Albums.DeleteModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<div>
    
    <form method="post">
        @*<input type="hidden" asp-for="Album.AlbumId" />*@
        <input type="submit" value="Delete" asp-route-id="@Model.Album.AlbumId" class="btn btn-danger" /> |
        <a asp-page="/Index">Back to List</a>
    </form>
</div>

修改后结果如下(在我的机器上测试你的样本后,我已经删除了):

这里有一些关于 Asp.net 核心 Razor 页面路由和事件处理程序的参考资料,您可以参考它们:

Razor Pages in ASP.NET Core

Razor Pages Routing

Handler Methods in Razor Pages

详细更新页面资源如下:

album.cshtml:

@page
@model Project.Pages.AlbumsModel            
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<div class="row">
    <h1 class="display-2">Albums</h1>
    <table class="table">
        <thead class="thead-inverse">
            <tr>
                <th>Album ID, artist ID, Album title</th>
            </tr>
        </thead>
        <tbody>
            @foreach (string album in Model.Albums)
            {
                <tr>
                    <td>@album</td>
                    <td><a asp-page="/Albums/Delete" asp-route-id="@album">Delete</a></td>
                </tr>
            }
        </tbody>
    </table>
</div>
<div class="row">
    <p>Enter a title & ArtistID for a new album:&nbsp;</p>
    <form method="POST">
        <div><input asp-for="Album.Title" /></div>
        <div><input asp-for="Album.ArtistId" /></div>
        <input type="submit" />
    </form>
        @* <p>Enter a value and Album ID for a new album title:&nbsp;</p>
    <form method="POST">
        <div><input asp-for="Album.Title" /></div>
        <div><input asp-for="Album.AlbumId" /></div>
        <input type="submit" />
    </form> *@
</div>

album.cshtml.cs:

using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using System;

namespace Project.Pages
{
    public class AlbumsModel : PageModel
    {
        private Chinook db;

        public AlbumsModel(Chinook injectedContext)
        {
            db = injectedContext;
        }
        public IEnumerable<string> Albums { get; set; }
        public void OnGet()
        {
            ViewData["Title"] = "Chinook Web Site - Albums";
            // Albums = db.Albums.Select(s => s.Title);
            Albums = db.Albums.Select(s => s.AlbumId.ToString() + ". " + s.ArtistId + ". " + s.Title);
        }
        [BindProperty]
        public Album Album { get; set; }

        public IActionResult OnPost()
        {
            if (ModelState.IsValid)
            {
                db.Albums.Add(Album);
                db.SaveChanges();
                return RedirectToPage("/albums");
            }
            return Page();
        }

        // void RemoveAlbum(int albumId)
        // {
        //     var album = db.Albums.Find(albumId);
        //     if (album == null)
        //         throw new ArgumentOutOfRangeException();
        //     db.Albums.Remove(album);
        //     db.SaveChanges();
        // }

        public IActionResult DeleteAlbum(int AlbumId)
        {
            var album = db.Albums.Find(AlbumId);

            if (album == null) return Page();

            db.Albums.Remove(album); db.SaveChanges(); return RedirectToPage("/albums");
        }
    }
}

Delete.cshtml:

@page  "{id?}"
@model Project.Pages.Albums.DeleteModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{ ViewData["Title"] = "Delete"; }

<h1>Delete</h1>

<p class="text-danger">@Model.ErrorMessage</p>

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

    <form method="post">
        @*<input type="hidden" asp-for="Album.AlbumId" />*@
        <input type="submit" value="Delete" asp-route-id="@Model.Album.AlbumId" class="btn btn-danger" /> |
        <a asp-page="/Index">Back to List</a>
    </form>
</div>

Delete.cshtml.cs:

#region snippet_All
using Project.Models; //using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;

namespace Project.Pages.Albums //ContosoUniversity.Pages.Students
{
    public class DeleteModel : PageModel
    {
        private readonly Chinook _context;

        public DeleteModel(Chinook context)
        {
            _context = context;
        }

        [BindProperty]
        public Album Album { get; set; }
        public string ErrorMessage { get; set; }

        public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false)
        {

            if (id == null)
            {
                return NotFound();
            }

            var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);

            Album = await _context.Albums
                .AsNoTracking()
                .FirstOrDefaultAsync(m => m.AlbumId == albumid);

            if (Album == null)
            {
                return NotFound();
            }

            if (saveChangesError.GetValueOrDefault())
            {
                ErrorMessage = "Delete failed. Try again";
            }

            return Page();
        }

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

            var album = await _context.Albums.FindAsync(id);

            if (album == null)
            {
                return NotFound();
            }

            try
            {
                //_context.Albums.Remove(album);
                //await _context.SaveChangesAsync();
                return RedirectToPage("/Index");
            }
            catch (DbUpdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log.)
                return RedirectToAction("/Albums/Delete",
                                     new { id, saveChangesError = true });
            }
        }
    }
}
#endregion