尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

.NET 10全栈开发实战:手把手构建CRUD任务管理Web应用

.NET 10全栈开发实战:手把手构建CRUD任务管理Web应用 如果你是一名刚接触 .NET 全栈开发的新手面对 C#、ASP.NET Core、EF Core、SQL Server 这一长串技术栈是不是感觉有点无从下手网上教程要么只讲后端 API要么只讲前端页面或者数据库操作一笔带过很难找到一个真正从零开始、贯穿前后端和数据库的完整实战指南。这篇文章要解决的正是这个痛点。我们将使用.NET 10、ASP.NET Core MVC、Entity Framework Core和SQL Server 2025配合Bootstrap 5手把手构建一个具备完整 CRUD增删改查功能的“任务管理”Web应用。这不仅是技术栈的简单堆砌更重要的是理解它们如何协同工作形成一个清晰、可维护的全栈开发流程。我的核心判断是对于新手而言全栈开发的关键不在于精通每一门技术的所有细节而在于快速搭建一个“端到端”的闭环理解数据如何从用户界面经过控制器、模型层最终持久化到数据库并反向展示。本文将提供一个这样的闭环并重点指出新手最容易混淆和踩坑的几个环节比如模型绑定、EF Core 迁移、布局页面的使用以及 Bootstrap 的快速集成。读完本文你将能独立搭建一个具备基础业务逻辑的现代 .NET Web 应用骨架。1. 为什么选择这个技术栈它能解决什么问题在开始写代码之前我们先明确一下这个技术组合的定位和优势。这有助于你理解为什么学它以及它适合做什么。C# 与 .NET 10C# 是一门强类型、面向对象的现代编程语言语法优雅生态成熟。.NET 10 是微软最新的统一开发平台它高性能、跨平台Windows, Linux, macOS并且拥有长期支持LTS版本是企业级和现代云原生应用的首选之一。选择 .NET 10 意味着你能用到最新的语言特性和运行时优化。ASP.NET Core MVC这是一个基于模型-视图-控制器设计模式的 Web 应用框架。对于全栈新手MVC 模式提供了非常清晰的责任分离Model处理数据和业务逻辑View负责呈现用户界面Controller作为中间人协调两者。这种结构比单纯的 Web API 前端框架如 React/Vue的组合在入门阶段更容易理解整个请求-响应周期。Entity Framework Core (EF Core)这是 .NET 官方的对象关系映射器ORM。它的核心价值是让你能用 C# 对象和 LINQ 查询来操作数据库而无需编写大量的原始 SQL。对于新手这极大地降低了数据库操作的门槛让你更专注于业务逻辑。SQL Server 2025作为微软旗舰级的关系型数据库它性能强大、功能全面并且与 .NET 生态集成度极高。使用它作为起点可以学习到标准的数据库设计、事务管理等概念。本文也会使用 LocalDBSQL Server Express 的轻量级版本进行本地开发无需复杂安装。Bootstrap 5一个流行的前端 CSS 框架。它提供了一套响应式、移动设备优先的网格系统和预制组件按钮、表单、导航栏等。对于后端开发者或不擅长前端设计的新手Bootstrap 能让你快速构建出美观、专业的界面而无需深入 CSS 细节。这个组合解决了什么问题它解决了新手从“学习语法”到“做出一个有用东西”之间的鸿沟。你不再需要分别寻找 C# 教程、Web 开发教程、数据库教程然后艰难地将它们拼凑起来。这个技术栈提供了一个内聚的、官方支持的、企业级验证过的全栈解决方案。你将从创建一个项目开始一步步看到数据如何流动最终形成一个可运行的 Web 应用。2. 环境准备与工具安装工欲善其事必先利其器。以下是开始前必须准备好的环境。2.1 安装 .NET SDK 10.NET SDK 包含了运行和构建 .NET 应用所需的一切运行时、CLI 工具等。访问官网打开 .NET 下载页面 。选择版本下载并安装.NET 10.0 SDK选择与您操作系统对应的安装包如 Windows x64 Installer。验证安装打开命令行CMD, PowerShell 或终端输入以下命令dotnet --version如果安装成功将显示版本号例如10.0.3xx。2.2 安装集成开发环境 (IDE)强烈推荐使用Visual Studio 2022社区版免费或Visual Studio Code。Visual Studio 2022功能最全对 .NET 和 SQL Server 支持最好开箱即用。下载时确保勾选“ASP.NET 和 Web 开发”工作负载。Visual Studio Code轻量级跨平台。需要额外安装C# 扩展由 Microsoft 发布。2.3 安装 SQL Server 2025 与 SQL Server Management Studio (SSMS)安装 SQL Server 2025 Developer Edition这是免费版本功能齐全仅用于开发和测试。从微软官网下载安装程序。在安装过程中选择“基本”安装类型通常最简单它会自动安装 SQL Server 2025 和 SQL Server Express LocalDB。安装 SSMS这是一个用于管理 SQL Server 数据库的图形化工具。同样从微软官网免费下载安装。验证 LocalDB安装后LocalDB 通常已可用。在命令行中尝试连接sqllocaldb info如果列出实例如MSSQLLocalDB说明安装成功。2.4 验证环境创建一个简单的控制台项目来测试环境dotnet new console -n HelloDotNet cd HelloDotNet dotnet run你应该看到输出“Hello, World!”。至此基础环境就绪。3. 创建项目与理解 MVC 结构让我们从零开始创建项目并理解生成的文件结构。3.1 创建 ASP.NET Core MVC 项目打开命令行导航到你的工作目录执行dotnet new mvc -n TaskManager --no-https -o .mvc指定项目模板。-n TaskManager项目名称。--no-https为了简化开发暂时禁用 HTTPS 重定向生产环境必须启用。-o .在当前目录创建。或者在 Visual Studio 2022 中文件-新建-项目- 搜索“ASP.NET Core Web App (Model-View-Controller)”。3.2 项目结构解析创建后你会看到类似如下的目录结构TaskManager/ ├── Controllers/ # 控制器目录 │ └── HomeController.cs # 默认主页控制器 ├── Models/ # 模型目录 (我们主要在这里工作) ├── Views/ # 视图目录 │ ├── Home/ # Home控制器对应的视图 │ └── Shared/ # 共享视图如布局页 ├── wwwroot/ # 静态资源CSS, JS, 图片 ├── appsettings.json # 应用配置文件数据库连接字符串在这里 ├── Program.cs # 应用入口点配置服务和中间件管道 └── TaskManager.csproj # 项目文件管理依赖MVC 流程简述用户访问一个 URL如/Task/Index。路由系统将请求映射到TaskController中的Index方法。Controller中的Index方法执行它可能会使用Model或通过 EF Core 从数据库获取数据然后将数据打包到ViewBag、ViewData或一个强类型模型对象中。Controller 方法返回一个View()结果指定渲染哪个View文件通常位于Views/Task/Index.cshtml。View接收 Controller 传递过来的数据并生成最终的 HTML 页面返回给用户的浏览器。4. 定义数据模型与数据库上下文我们的应用是“任务管理”所以核心模型是TaskItem。4.1 创建数据模型在Models文件夹下新建一个类文件TaskItem.cs// Models/TaskItem.cs using System; using System.ComponentModel.DataAnnotations; namespace TaskManager.Models { public class TaskItem { public int Id { get; set; } // 主键EF Core 默认将名为 Id 或 类名Id 的属性设为主键 [Required(ErrorMessage 任务标题是必填项)] [StringLength(100, ErrorMessage 标题长度不能超过100个字符)] [Display(Name 任务标题)] public string Title { get; set; } [Display(Name 任务描述)] [DataType(DataType.MultilineText)] public string? Description { get; set; } // 可空类型表示非必填 [Required(ErrorMessage 请选择任务状态)] [Display(Name 状态)] public bool IsCompleted { get; set; } false; // 默认未完成 [Required(ErrorMessage 截止日期是必填项)] [Display(Name 截止日期)] [DataType(DataType.Date)] public DateTime DueDate { get; set; } DateTime.Now.AddDays(7); // 默认一周后 [Display(Name 创建时间)] [DataType(DataType.DateTime)] public DateTime CreatedAt { get; set; } DateTime.Now; // 自动设置 } }关键点[Required],[StringLength]是数据注解用于前端和后端验证。[Display]注解定义了在表单标签中显示的友好名称。DataType注解帮助 MVC 框架在渲染视图时选择正确的 HTML5 输入类型。使用可空引用类型 (string?) 是一个好习惯需要项目文件启用Nullableenable/Nullable。4.2 创建数据库上下文 (DbContext)DbContext 是 EF Core 的核心它代表与数据库的一个会话用于查询和保存数据。在Models文件夹下新建ApplicationDbContext.cs// Models/ApplicationDbContext.cs using Microsoft.EntityFrameworkCore; namespace TaskManager.Models { public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptionsApplicationDbContext options) : base(options) { } // 将 TaskItem 模型映射到数据库中的 Tasks 表 public DbSetTaskItem Tasks { get; set; } // 可以在此处重写 OnModelCreating 方法进行更复杂的模型配置如索引、关系 // protected override void OnModelCreating(ModelBuilder modelBuilder) // { // // 示例为 Title 添加索引 // modelBuilder.EntityTaskItem() // .HasIndex(t t.Title); // } } }4.3 配置数据库连接字符串打开appsettings.json文件添加一个连接字符串。我们将使用 LocalDB。{ Logging: { LogLevel: { Default: Information, Microsoft.AspNetCore: Warning } }, ConnectionStrings: { DefaultConnection: Server(localdb)\\mssqllocaldb;DatabaseTaskManagerDB;Trusted_ConnectionTrue;MultipleActiveResultSetstrue;TrustServerCertificateTrue }, AllowedHosts: * }(localdb)\\mssqllocaldbLocalDB 的默认实例名。TaskManagerDB我们要创建的数据库名称。TrustServerCertificateTrue在本地开发时简化连接避免证书验证错误。4.4 在 Program.cs 中注册服务打开Program.cs这是 ASP.NET Core 应用的启动配置中心。// Program.cs using Microsoft.EntityFrameworkCore; using TaskManager.Models; var builder WebApplication.CreateBuilder(args); // 添加数据库上下文服务使用 SQL Server builder.Services.AddDbContextApplicationDbContext(options options.UseSqlServer(builder.Configuration.GetConnectionString(DefaultConnection))); // 添加 MVC 服务 builder.Services.AddControllersWithViews(); var app builder.Build(); // 配置 HTTP 请求管道中间件 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler(/Home/Error); app.UseHsts(); // 生产环境使用严格的 HTTP 安全传输协议 } app.UseHttpsRedirection(); // 将 HTTP 请求重定向到 HTTPS我们创建时用了 --no-https所以暂时注释掉或保留 app.UseStaticFiles(); // 启用静态文件服务wwwroot 下的文件 app.UseRouting(); // 启用路由 app.UseAuthorization(); // 启用授权本文暂不涉及 app.MapControllerRoute( name: default, pattern: {controllerHome}/{actionIndex}/{id?}); // 默认路由 app.Run();5. 使用 EF Core 迁移创建数据库我们定义了模型和上下文但数据库还没有对应的表。EF Core 迁移功能可以帮我们根据模型变化生成 SQL 脚本来更新数据库架构。5.1 安装 EF Core 工具包如果未安装在项目根目录TaskManager.csproj所在目录打开命令行执行dotnet tool install --global dotnet-ef或者如果已安装但需要更新dotnet tool update --global dotnet-ef5.2 添加 EF Core 设计包确保项目文件 (TaskManager.csproj) 中包含了必要的 NuGet 包。通常 MVC 项目模板已包含Microsoft.EntityFrameworkCore.SqlServer。我们还需要设计时包来支持迁移命令。在命令行中执行dotnet add package Microsoft.EntityFrameworkCore.Design5.3 创建并应用初始迁移创建迁移此命令会扫描你的DbContext和模型与当前数据库状态目前为空对比生成一个迁移文件。dotnet ef migrations add InitialCreate执行后项目中会生成一个Migrations文件夹里面包含以时间戳命名的迁移文件如20250408012345_InitialCreate.cs和快照文件。更新数据库此命令将迁移文件中定义的更改应用到实际的 SQL Server 数据库。dotnet ef database update执行成功后SSMS 中连接到(localdb)\MSSQLLocalDB就能看到新创建的TaskManagerDB数据库和Tasks表。迁移的意义迁移是数据库的版本控制。当你后续修改了TaskItem模型比如添加一个Priority字段可以再创建新的迁移 (AddPriorityToTask)然后更新数据库。这比直接删除数据库重建要安全得多尤其是在生产环境。6. 实现控制器与视图CRUD 操作现在我们来实现核心的业务功能任务的创建、读取、更新和删除。6.1 创建 TasksController在Controllers文件夹上右键 -添加-控制器- 选择“包含视图的 MVC 控制器使用 Entity Framework”。模型类TaskManager.Models.TaskItem数据上下文类TaskManager.Models.ApplicationDbContext控制器名称TasksController注意复数点击“添加”Visual Studio 会自动生成包含完整 CRUD 操作和视图的控制器和视图文件。这是学习 MVC 脚手架代码的绝佳方式。我们也可以手动创建。以下是TasksController.cs的核心代码// Controllers/TasksController.cs using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TaskManager.Models; using System.Diagnostics; namespace TaskManager.Controllers { public class TasksController : Controller { private readonly ApplicationDbContext _context; public TasksController(ApplicationDbContext context) { _context context; // 依赖注入 } // GET: Tasks public async TaskIActionResult Index(string searchString, bool? showCompleted) { var tasks from t in _context.Tasks select t; // 搜索过滤 if (!string.IsNullOrEmpty(searchString)) { tasks tasks.Where(t t.Title.Contains(searchString) || (t.Description ! null t.Description.Contains(searchString))); } // 状态过滤 if (showCompleted.HasValue) { tasks tasks.Where(t t.IsCompleted showCompleted.Value); } // 按截止日期排序 tasks tasks.OrderBy(t t.DueDate).ThenByDescending(t t.CreatedAt); // 将过滤条件传递给视图用于保持表单状态 ViewData[CurrentFilter] searchString; ViewData[ShowCompleted] showCompleted; return View(await tasks.AsNoTracking().ToListAsync()); } // GET: Tasks/Details/5 public async TaskIActionResult Details(int? id) { if (id null) { return NotFound(); } var taskItem await _context.Tasks .FirstOrDefaultAsync(m m.Id id); if (taskItem null) { return NotFound(); } return View(taskItem); } // GET: Tasks/Create public IActionResult Create() { return View(); } // POST: Tasks/Create [HttpPost] [ValidateAntiForgeryToken] public async TaskIActionResult Create([Bind(Id,Title,Description,IsCompleted,DueDate)] TaskItem taskItem) { // 手动设置创建时间 taskItem.CreatedAt DateTime.Now; if (ModelState.IsValid) { _context.Add(taskItem); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } return View(taskItem); } // GET: Tasks/Edit/5 public async TaskIActionResult Edit(int? id) { if (id null) { return NotFound(); } var taskItem await _context.Tasks.FindAsync(id); if (taskItem null) { return NotFound(); } return View(taskItem); } // POST: Tasks/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public async TaskIActionResult Edit(int id, [Bind(Id,Title,Description,IsCompleted,DueDate,CreatedAt)] TaskItem taskItem) { if (id ! taskItem.Id) { return NotFound(); } if (ModelState.IsValid) { try { _context.Update(taskItem); await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TaskItemExists(taskItem.Id)) { return NotFound(); } else { throw; } } return RedirectToAction(nameof(Index)); } return View(taskItem); } // GET: Tasks/Delete/5 public async TaskIActionResult Delete(int? id) { if (id null) { return NotFound(); } var taskItem await _context.Tasks .FirstOrDefaultAsync(m m.Id id); if (taskItem null) { return NotFound(); } return View(taskItem); } // POST: Tasks/Delete/5 [HttpPost, ActionName(Delete)] [ValidateAntiForgeryToken] public async TaskIActionResult DeleteConfirmed(int id) { var taskItem await _context.Tasks.FindAsync(id); if (taskItem ! null) { _context.Tasks.Remove(taskItem); await _context.SaveChangesAsync(); } return RedirectToAction(nameof(Index)); } private bool TaskItemExists(int id) { return _context.Tasks.Any(e e.Id id); } } }关键点解析依赖注入控制器通过构造函数接收ApplicationDbContext实例这是 ASP.NET Core 内置的依赖注入容器自动提供的。异步编程使用async/await和ToListAsync()、FindAsync()等方法避免阻塞线程提高应用吞吐量。模型绑定[Bind]特性指定了哪些属性可以从 HTTP 请求中绑定到模型这是一种防止过度发布攻击的安全措施。验证ModelState.IsValid会检查模型上的数据注解如[Required]是否通过。[ValidateAntiForgeryToken]防止跨站请求伪造攻击与视图中的Html.AntiForgeryToken()配合使用。6.2 创建对应的视图视图文件位于Views/Tasks目录下。我们以Index.cshtml和Create.cshtml为例。Index.cshtml (列表与搜索视图)* Views/Tasks/Index.cshtml * model IEnumerableTaskManager.Models.TaskItem { ViewData[Title] 任务列表; } h1任务列表/h1 p a asp-actionCreate classbtn btn-primary创建新任务/a /p form asp-actionIndex methodget classrow g-3 mb-4 div classcol-auto input typetext namesearchString classform-control placeholder搜索标题或描述... valueViewData[CurrentFilter] / /div div classcol-auto select nameshowCompleted classform-select asp-items(new SelectList(new ListSelectListItem { new SelectListItem { Text 全部, Value }, new SelectListItem { Text 仅未完成, Value false }, new SelectListItem { Text 仅已完成, Value true } }, Value, Text, ViewData[ShowCompleted])) /select /div div classcol-auto button typesubmit classbtn btn-outline-secondary筛选/button a asp-actionIndex classbtn btn-link重置/a /div /form table classtable table-striped table-hover thead tr thHtml.DisplayNameFor(model model.Title)/th thHtml.DisplayNameFor(model model.Description)/th thHtml.DisplayNameFor(model model.DueDate)/th thHtml.DisplayNameFor(model model.IsCompleted)/th th操作/th /tr /thead tbody foreach (var item in Model) { tr tdHtml.DisplayFor(modelItem item.Title)/td tdHtml.DisplayFor(modelItem item.Description)/td tdHtml.DisplayFor(modelItem item.DueDate)/td td if (item.IsCompleted) { span classbadge bg-success已完成/span } else { span classbadge bg-warning text-dark进行中/span } /td td a asp-actionDetails asp-route-iditem.Id classbtn btn-sm btn-info详情/a a asp-actionEdit asp-route-iditem.Id classbtn btn-sm btn-warning编辑/a a asp-actionDelete asp-route-iditem.Id classbtn btn-sm btn-danger删除/a /td /tr } /tbody /tableCreate.cshtml (创建任务视图)* Views/Tasks/Create.cshtml * model TaskManager.Models.TaskItem { ViewData[Title] 创建任务; } h1创建新任务/h1 hr / div classrow div classcol-md-6 form asp-actionCreate div asp-validation-summaryModelOnly classtext-danger/div * 显示模型级错误 * Html.AntiForgeryToken() * 生成防伪令牌 * div classform-group mb-3 label asp-forTitle classcontrol-label/label input asp-forTitle classform-control / span asp-validation-forTitle classtext-danger/span * 显示字段级错误 * /div div classform-group mb-3 label asp-forDescription classcontrol-label/label textarea asp-forDescription classform-control rows3/textarea span asp-validation-forDescription classtext-danger/span /div div classform-group mb-3 label asp-forDueDate classcontrol-label/label input asp-forDueDate classform-control typedate / span asp-validation-forDueDate classtext-danger/span /div div classform-group form-check mb-3 input asp-forIsCompleted classform-check-input / label asp-forIsCompleted classform-check-label/label span asp-validation-forIsCompleted classtext-danger/span /div div classform-group input typesubmit value创建 classbtn btn-primary / a asp-actionIndex classbtn btn-secondary返回列表/a /div /form /div /div section Scripts { {await Html.RenderPartialAsync(_ValidationScriptsPartial);} }视图关键点Tag Helpersasp-action,asp-for,asp-validation-for等是 ASP.NET Core 的 Tag Helpers它们在服务器端渲染成正确的 HTML简化了代码并提供了强类型支持。布局页视图默认使用Views/Shared/_Layout.cshtml作为布局。我们将在下一步集成 Bootstrap。客户端验证section Scripts引入了 jQuery 验证脚本实现了基于数据注解的客户端验证无需编写 JavaScript。7. 集成 Bootstrap 5 美化界面默认的 MVC 模板可能样式简单。我们快速集成 Bootstrap 5 来获得现代化的外观。7.1 安装 Bootstrap最简单的方式是通过 LibMan库管理器或 CDN。这里使用 CDN修改布局页。打开Views/Shared/_Layout.cshtml找到head部分替换或添加 Bootstrap CSS 和 JS 的 CDN 链接。!DOCTYPE html html langen head meta charsetutf-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleViewData[Title] - TaskManager/title !-- Bootstrap 5 CSS -- link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/css/bootstrap.min.css relstylesheet !-- 可选的 Bootstrap 图标 -- link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap-icons1.10.0/font/bootstrap-icons.css link relstylesheet href~/css/site.css asp-append-versiontrue / /head body header nav classnavbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3 div classcontainer-fluid a classnavbar-brand asp-area asp-controllerHome asp-actionIndexTaskManager/a button classnavbar-toggler typebutton>dotnet run或直接在 Visual Studio 中按 F5。浏览器打开https://localhost:5001或http://localhost:5000取决于你的配置。点击导航栏的“任务管理”即可进入我们刚创建的功能页面。尝试创建、编辑、删除、搜索任务。8. 常见问题与排查思路在开发过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案dotnet ef命令未找到EF Core 工具未全局安装或未添加到 PATH。在命令行输入dotnet ef。运行dotnet tool install --global dotnet-ef。确保安装后重启命令行。迁移时出现No database provider has been configuredApplicationDbContext未在Program.cs中注册或注册的选项未配置数据库提供程序。检查Program.cs中是否有builder.Services.AddDbContextApplicationDbContext(...)并且使用了UseSqlServer。确保正确添加了Microsoft.EntityFrameworkCore.SqlServerNuGet 包并在Program.cs中完成配置。运行应用时出现SqlException: Cannot open database数据库不存在或连接字符串错误。LocalDB 实例未启动。1. 检查appsettings.json中的连接字符串。2. 在命令行运行sqllocaldb info和sqllocaldb start MSSQLLocalDB。1. 确保连接字符串中的数据库名正确。2. 启动 LocalDB 实例。如果数据库不存在确保已运行dotnet ef database update。页面显示InvalidOperationException: Unable to resolve service for type ...DbContext控制器请求DbContext但未在Program.cs的ConfigureServices或builder.Services中注册。检查Program.cs中是否调用了AddDbContext。在Program.cs中添加builder.Services.AddDbContextApplicationDbContext(...)。修改模型后创建新迁移失败模型更改与现有数据库架构冲突或者有未应用的迁移。运行dotnet ef migrations list查看所有迁移。检查上次迁移是否已应用。1. 先确保所有迁移都已应用 (dotnet ef database update)。2. 再创建新迁移 (dotnet ef migrations add AddNewField)。3. 如果冲突严重可考虑删除Migrations文件夹和数据库从头开始仅限开发环境。Bootstrap 样式未生效CDN 链接失效或本地 CSS/JS 文件覆盖了 Bootstrap 样式或 HTML 结构不符合 Bootstrap 要求。1. 浏览器开发者工具检查网络请求看 Bootstrap CSS/JS 是否加载成功。2. 检查控制台是否有 JS 错误。3. 检查元素是否应用了正确的 Bootstrap 类。1. 更新 CDN 链接到最新稳定版。2. 确保 Bootstrap JS 在页面底部引入且 jQuery如果需要在它之前。3. 参考 Bootstrap 官方文档检查 HTML 结构。表单提交后验证错误信息未显示未在视图中引入验证脚本或者ModelState在控制器中被清除。1. 检查Create.cshtml或Edit.cshtml底部是否有section Scripts引入验证脚本。2. 在控制器 POST 方法中设置断点检查ModelState.IsValid值。1. 确保视图包含了{await Html.RenderPartialAsync(_ValidationScriptsPartial);}。2. 确保模型属性上有正确的数据注解。9. 最佳实践与进阶建议完成基础功能后以下建议能让你的项目更健壮、更专业使用仓储模式 (Repository Pattern)不要在控制器中直接使用DbContext。创建一个仓储接口如ITaskRepository和实现类将数据访问逻辑封装起来。这使代码更可测试、更清晰。依赖注入你已经看到了控制器如何注入DbContext。对于服务层、仓储层也应通过接口注入而不是new实例。异步编程始终对 I/O 操作如数据库查询、文件读写、网络请求使用异步方法 (async/await)以提升应用响应能力。错误处理在Program.cs中使用UseExceptionHandler中间件处理生产环境错误。在开发中使用开发者异常页面。考虑使用全局异常过滤器进行更细粒度的控制。日志记录使用 ASP.NET Core 内置的日志接口 (ILoggerT)而不是Console.WriteLine。这便于集中管理和查看日志。配置管理将连接字符串、API 密钥等敏感信息放在appsettings.Development.json开发和appsettings.Production.json生产中或使用环境变量、Azure Key Vault 等安全方式。前端优化考虑使用Bundling Minification打包和压缩 CSS/JS 文件。对于更复杂的交互可以逐步引入JavaScript 前端框架如 Vue.js 或 React并通过 Web API 与后端通信。此时ASP.NET Core MVC 可以退化为只提供 API 的 backend。安全性HTTPS生产环境务必启用 HTTPS。SQL 注入使用 EF Core 的参数化查询已能有效防止避免拼接 SQL 字符串。XSSRazor 视图默认会对输出进行 HTML 编码防止跨站脚本攻击。对于需要渲染 HTML 的内容使用Html.Raw()要极其小心。CSRF确保 POST、PUT、DELETE 等方法有[ValidateAntiForgeryToken]特性。部署可以将应用发布到Azure App Service、Docker 容器或任何支持 .NET 的 Linux/Windows 服务器上。使用dotnet publish命令生成部署包。通过这个完整的“任务管理”项目实战你不仅学会了如何使用 C#、.NET 10、ASP.NET Core MVC、EF Core 和 SQL Server 构建一个功能完整的 Web 应用更重要的是理解了全栈开发中各个组件如何连接与协作。下一步你可以尝试为任务添加“分类”、“优先级”、“附件”等功能或者引入用户身份认证使用 ASP.NET Core Identity将应用扩展为一个真正的多用户系统。这个技术栈为你打下了坚实的地基足以支撑你向更复杂的企业级应用迈进。
返回列表