在 ASP.NET Core 專案中加入使用 Entity Framework Core 的 Razor Page
Adding a Razor Page with Entity Framework Core to an ASP.NET Core Project
文章示範如何在 ASP.NET Core 專案中加入 Razor Page,使用 Entity Framework Core 存取現有的 SQL Server 資料庫,並改善產生頁面的響應式設計。內容包括以 Bootstrap 圖示取代 CRUD 連結、用 Bootstrap 對話框確認刪除,以及以套用 Bootstrap 樣式的 DIV 元素取代表格。
Introduction
Learn how to add a Razor Page that reads and writes data using Entity Framework Core (EF Core), in this case from an existing SQL Server database reverse-engineered using the EF Power Tools Visual Studio extension.
Although Visual Studio does a decent job of adding these pages, several improvements are recommended and will be covered with code samples.
For displaying lists, developers not interested in meeting WCAG AA standards should make several improvements, while developers wanting to comply with WCAG AA should move from tables to divs.
Objective
To improve responsiveness of generated pages, replace CRUD links with Bootstrap icons and replace the delete page with a Bootstrap dialog. The main change is moving from a table-centric model to using a DIV model with Bootstrap styles.
Setup
- Create a new ASP.NET Core project rather than a current project
- Create a DbContext and models to access your data.
- Make sure there is a decent amount of data in the database to work with
- In addition to your EF Core data provider, add the following NuGet packages.
- Microsoft.EntityFrameworkCore.Tools
- Microsoft.VisualStudio.Web.CodeGeneration.Design
Add list page
- From Solution Explorer, right-click on the
Pagesfolder - Select
Add,Razor page - From the dialog select option 2, click
Add.
- Next dialog: populate page name, select template index, select model, and DbContext.
- Click
Add - Code is then generated.
- Add a link to the page in _Layout.cshtml
- Run the project and something like shown below (links will not work until those pages are created as done with the current page)
List page modifications
Change links
The first modification changes the following links to Bootstrap-icon-styled links. This is because users tend to associate images better than text.
- From Solution Explorer
- Right-click, select Add
- Client library, select Bootstrap icons and click Install
- Add the following to the head section of _Layout.cshtml
<link href="~/lib/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet" />
In the list page replace
<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>
With
<td>
@* Added by Karen *@
<a asp-page="./CustomerEditPage"
asp-route-id="@item.Id"
asp-route-returnUrl="@($"{Request.Path}{Request.QueryString}")"
class="btn btn-sm btn-outline-primary"
title="Edit">
<i class="bi bi-pencil"></i>
</a>
<a asp-page="./Details" asp-route-id="@item.Id" class="btn btn-sm btn-outline-dark" title="Details">
<i class="bi bi-eye"></i>
</a>
<button type="button"
class="btn btn-sm btn-outline-danger"
title="Delete"
aria-label="Delete @item.Company"
data-bs-toggle="modal"
data-bs-target="#deleteModal"
data-customer-id="@item.Id"
data-customer-name="@item.Company">
<i class="bi bi-trash"></i>
</button>
</td>
Customize delete action
The standard method is to scaffold a delete page that, when clicked from the list page, asks to confirm removal of the current record.
A better option is to use a Bootstrap dialog. The following has the Cancel button as the default.
The trigger
Dialog
<div class="modal fade"
id="deleteModal"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">
Confirm Delete
</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close">
</button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete this customer?</p>
<p class="fw-bold" id="customerName"></p>
<p class="text-danger mb-0">
This action cannot be undone.
</p>
</div>
<div class="modal-footer">
<button type="button"
id="cancelDeleteButton"
class="btn btn-secondary"
data-bs-dismiss="modal">
Cancel
</button>
<form method="post" asp-page-handler="Delete">
<input type="hidden"
name="id"
id="deleteCustomerId" />
<button type="submit" class="btn btn-danger">
<i class="bi bi-trash me-1"></i>
Delete
</button>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
const deleteModal = document.getElementById("deleteModal");
deleteModal.addEventListener("show.bs.modal", function(event) {
const button = event.relatedTarget;
document.getElementById("deleteCustomerId").value =
button.getAttribute("data-customer-id");
document.getElementById("customerName").textContent =
button.getAttribute("data-customer-name");
});
deleteModal.addEventListener("shown.bs.modal", function() {
document.getElementById("cancelDeleteButton").focus();
});
</script>
Backend database code
public async Task<IActionResult> OnPostDeleteAsync(int id)
{
var customer = await context.Customers.FindAsync(id);
if (customer is null)
{
return NotFound();
}
context.Customers.Remove(customer);
await context.SaveChangesAsync();
return RedirectToPage();
}
Edit/Create pages
Is created the same as the list page.
In the sample code FluentValidation is used to validate entries.
#nullable disable
using FluentValidation;
using TablesVsDivsSample1App.Models;
namespace TablesVsDivsSample1App.Validators;
/// <summary>
/// Provides validation rules for the <see cref="Customers"/> model.
/// </summary>
public class CustomersValidator : AbstractValidator<Customers>
{
public CustomersValidator()
{
RuleFor(x => x.Company).NotEmpty();
RuleFor(x => x.ContactType).NotEmpty();
RuleFor(x => x.ContactName).NotEmpty();
RuleFor(x => x.Country).NotEmpty();
RuleFor(x => x.JoinDate)
.GreaterThanOrEqualTo(new DateOnly(1900, 1, 1))
.WithMessage("Join Date must be on or after 01/01/1900.")
.LessThanOrEqualTo(DateOnly.FromDateTime(DateTime.Today))
.WithMessage($"Join Date must be on or before {DateOnly.FromDateTime(DateTime.Today):MM/dd/yyyy}.");
}
}
Tables to DIV responsive design
Using DIV elements with Bootstrap classes provides better responsiveness than using tables.
To move from tables to DIV elements with Bootstrap classes, easily attach the stock list page to a ChatGPT chat and tell it to use DIV elements with Bootstrap classes. Follow this up with the icon buttons and delete dialog.
| Page | Description |
|---|---|
| StandardView | Standard scaffolded view |
| UsingTablesPage | Modified view using tables |
| UsingDivsPage | Modified view using divs |
來源:DEV Community · dev.to







