ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C#全栈开发实战:从零构建ASP.NET Core MVC + EF Core + SQL Server任务管理应用

C#全栈开发实战:从零构建ASP.NET Core MVC + EF Core + SQL Server任务管理应用 上周帮一个刚转行做开发的朋友搭环境他盯着 Visual Studio 里密密麻麻的项目模板和 NuGet 包管理器问了我一个很直接的问题“我知道 C#、.NET、MVC、EF、SQL Server 这些词都很重要但把它们堆在一起到底怎么才能串成一个我能跑起来、能看懂、还能改的完整项目”这个问题很典型。很多新手在面对“全栈”这个词时容易陷入两个误区要么觉得必须把每个技术都学到专家级才能开始要么跟着教程一步步做完了却不知道每一步为什么这么做项目结构为什么这样设计一旦离开教程就无从下手。这篇文章我们就用C# .NET 10 ASP.NET Core MVC EF Core SQL Server这套经典且强大的组合来回答这个问题。我们的目标不是罗列每个技术的百科条目而是亲手搭建一个最小可用的“任务管理”Web应用并在这个过程中理解每一层技术如何分工协作以及一个全栈项目从零到一的构建逻辑。你会发现全栈开发的核心不是掌握无数碎片知识而是理解数据如何从数据库出发经过层层处理最终呈现在用户浏览器上的完整链路。1. 环境与项目初始化不是安装软件而是建立工作流在写第一行代码之前正确的环境准备能避免未来80%的“玄学”错误。我们的技术栈版本明确.NET 10 SDKSQL Server2022或2019均可本文以LocalDB为例它轻量且包含在SQL Server安装中以及一个IDEVisual Studio 2022 或 VS Code。1.1 核心工具安装与验证首先确保你的机器上安装了 .NET 10 SDK。打开命令行输入dotnet --version确认输出为10.x.x。如果没有去微软官网下载安装。这一步是基石所有后续命令都依赖它。接着是数据库。对于学习和开发我强烈建议使用SQL Server Express LocalDB。它在安装 Visual Studio 时通常作为“数据存储和处理”工作负载的一部分被勾选安装。你也可以单独安装 SQL Server Express。安装后你不需要手动启动一个数据库服务LocalDB会在应用首次连接时自动启动实例非常方便。验证方式打开命令行输入SqlLocalDB info如果能看到实例列表如MSSQLLocalDB说明安装成功。注意如果你遇到连接问题优先检查 LocalDB 实例名是否为(localdb)\MSSQLLocalDB这是默认实例名。很多新手教程忽略这一点导致连接字符串报错。1.2 创建项目理解模板背后的结构不要用 Visual Studio 的图形化向导直接创建一个包含所有功能的大项目。我们从最纯净的状态开始手动添加所需功能这样你才能看清每个组件的职责。打开命令行进入你的工作目录执行dotnet new webapp -n TaskManager -f net10.0这个命令创建了一个名为TaskManager的 ASP.NET Core Razor Pages 项目模板。等等我们不是要用 MVC 吗是的但 Razor Pages 模板是更简单的起点我们可以手动将其改造成 MVC这个过程本身极具教育意义。进入项目文件夹cd TaskManager。用你喜欢的编辑器如 VS Code打开它。观察初始结构Program.cs应用的入口和主要配置.NET 6 之后采用最小托管模型。appsettings.json配置文件比如数据库连接字符串。Pages/Razor Pages 的页面文件。wwwroot/静态资源CSS, JS, 图片。现在我们要将其转变为 MVC 项目。首先添加 MVC 支持所需的 NuGet 包和命名空间。实际上对于 Web App 模板MVC 服务已经隐含添加了我们主要需要调整的是路由和文件夹结构。1.3 改造为 MVC 结构创建文件夹在项目根目录下创建以下文件夹Controllers/Models/Views/修改Program.cs显式配置 MVC 服务并设置默认路由。找到var builder WebApplication.CreateBuilder(args);这行之后添加服务var builder WebApplication.CreateBuilder(args); // 添加 MVC 服务 builder.Services.AddControllersWithViews(); var app builder.Build(); // 配置 HTTP 请求管道 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler(/Home/Error); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); // 配置 MVC 默认路由 app.MapControllerRoute( name: default, pattern: {controllerHome}/{actionIndex}/{id?}); app.Run();删除或清空Pages文件夹因为我们不再使用 Razor Pages。现在你的项目骨架已经是一个标准的 MVC 结构了。为什么我们要手动改造而不是直接用dotnet new mvc因为理解一个框架的“组装”过程远比记住一个固定模板更重要。当你自己添加了AddControllersWithViews和MapControllerRoute你就明白了 MVC 模式是如何被注入到 ASP.NET Core 这个管道中的。下次遇到路由不工作、视图找不到的问题你就能直接定位到是服务没注册还是路由模式不匹配。2. 数据层构建用 EF Core 在代码和数据库之间架桥数据是应用的基石。这一层我们的目标是在 C# 中定义“任务”这个业务对象Model然后通过 EF Core 这个“翻译官”自动在 SQL Server 中创建对应的数据表并为我们提供便捷的数据操作方法。2.1 定义数据模型 (Model)在Models文件夹下创建一个类TaskItem.csnamespace TaskManager.Models { public class TaskItem { public int Id { get; set; } // 主键 public string Title { get; set; } string.Empty; public string? Description { get; set; } // 可空字段 public bool IsCompleted { get; set; } public DateTime CreatedDate { get; set; } DateTime.Now; } }这个类简单直接对应数据库里的一张表。Id属性会被 EF Core 默认识别为主键和自增列。注意string?的用法它表示这个字段在数据库里允许为 NULL在 C# 10 中这是推荐的可空引用类型写法能帮助减少运行时空引用异常。2.2 创建数据库上下文 (DbContext)DbContext 是 EF Core 的核心它代表与数据库的一次会话负责管理模型、跟踪实体状态、执行数据库操作。在Models文件夹下创建AppDbContext.csusing Microsoft.EntityFrameworkCore; namespace TaskManager.Models { public class AppDbContext : DbContext { public AppDbContext(DbContextOptionsAppDbContext options) : base(options) { } public DbSetTaskItem Tasks { get; set; } // 这行代码至关重要 // 可选在这里可以配置模型如字符串默认长度、索引等 protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 示例设置Title最大长度为100 modelBuilder.EntityTaskItem() .Property(t t.Title) .HasMaxLength(100); } } }DbSetTaskItem Tasks这一行就宣告了我们的应用中将有一个名为Tasks的集合对应数据库里的Tasks表。EF Core 会通过它来执行所有 CRUD 操作。2.3 连接数据库与依赖注入现在我们需要告诉应用使用哪个数据库并把AppDbContext注册到依赖注入容器中这样我们的控制器才能使用它。安装 EF Core 包在项目目录下执行命令。dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools第一个包是 SQL Server 数据库提供程序第二个包包含我们等下要用到的迁移工具命令。配置连接字符串打开appsettings.json添加一个连接字符串。{ ConnectionStrings: { DefaultConnection: Server(localdb)\\mssqllocaldb;DatabaseTaskManagerDB;Trusted_ConnectionTrue;MultipleActiveResultSetstrue;TrustServerCertificateTrue }, Logging: { LogLevel: { Default: Information, Microsoft.AspNetCore: Warning } }, AllowedHosts: * }连接字符串解读Server(localdb)\\mssqllocaldb连接到本地的 LocalDB 实例。注意是双反斜杠因为在 JSON 字符串中需要转义。DatabaseTaskManagerDB数据库名称如果不存在EF Core 会创建它。Trusted_ConnectionTrue使用 Windows 身份验证。MultipleActiveResultSetstrue允许在同一连接上执行多个查询对 MVC 应用很有用。TrustServerCertificateTrue本地开发时简化加密连接问题。在Program.cs中注册 DbContext 在builder.Services.AddControllersWithViews();之后添加// 从配置中读取连接字符串 var connectionString builder.Configuration.GetConnectionString(DefaultConnection); // 将 AppDbContext 注册为服务指定使用 SQL Server builder.Services.AddDbContextAppDbContext(options options.UseSqlServer(connectionString));2.4 数据库迁移让代码模型驱动数据库结构这是 EF Core 最强大的特性之一。我们不需要手动写 SQL 建表语句。创建迁移在项目根目录打开命令行执行dotnet ef migrations add InitialCreate这个命令会对比当前的AppDbContext特别是其中的DbSet和OnModelCreating配置与上一次迁移的状态目前是第一次生成一个名为InitialCreate的迁移文件存放在Migrations/文件夹下。打开这个文件夹你会看到XXXXXX_InitialCreate.cs文件里面是 EF Core 为你生成的、将要在数据库上执行的 C# 代码对应 SQL 操作。应用迁移更新数据库dotnet ef database update这个命令会执行迁移文件中记录的 SQL 命令在你的 SQL Server LocalDB 实例中创建TaskManagerDB数据库和Tasks表。关键理解迁移是 EF Core 的版本控制系统。每次你修改了数据模型比如给TaskItem加一个DueDate属性就再执行dotnet ef migrations add AddDueDate和dotnet ef database update。这保证了你的代码模型和数据库结构始终同步并且所有变更都可追溯。这是工程化开发的基础务必养成习惯。至此数据层搭建完毕。我们没写一行 SQL但数据库表已经就绪。这就是 ORM对象关系映射框架的价值让开发者用熟悉的面向对象方式操作数据。3. 业务逻辑与控制器MVC 中的“交通指挥”控制器是 MVC 模式中的“C”它接收用户请求协调模型数据和视图界面完成工作。在这一层我们的目标是创建TasksController实现对任务项的增删改查CRUD操作并处理好数据验证和异常。3.1 创建控制器与依赖注入 DbContext在Controllers文件夹上右键添加 - 控制器 - MVC 控制器 - 空命名为TasksController.cs。控制器需要访问数据库我们通过构造函数注入AppDbContextusing Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TaskManager.Models; namespace TaskManager.Controllers { public class TasksController : Controller { private readonly AppDbContext _context; // 依赖注入框架会自动提供 AppDbContext 的实例 public TasksController(AppDbContext context) { _context context; } // 后续的 Action 方法将在这里添加 } }private readonly AppDbContext _context;这个私有字段将用于所有 Action 方法中与数据库交互。依赖注入是 ASP.NET Core 的核心设计模式它使代码更可测试、更松耦合。3.2 实现 CRUD Action 方法我们将实现五个核心 ActionIndex: 显示任务列表。Create(GET POST): 显示创建表单和处理表单提交。Edit(GET POST): 显示编辑表单和处理表单提交。Delete(GET POST): 显示确认删除页面和处理删除请求。Details: 显示单个任务的详情。Index - 列表页// GET: Tasks public async TaskIActionResult Index() { // 异步查询所有任务按创建时间倒序排列 var tasks await _context.Tasks.OrderByDescending(t t.CreatedDate).ToListAsync(); return View(tasks); // 将任务列表传递给视图 }Create - 创建任务// GET: Tasks/Create public IActionResult Create() { return View(); // 返回一个空表单视图 } // POST: Tasks/Create [HttpPost] // 这个属性表示此方法只响应 HTTP POST 请求 [ValidateAntiForgeryToken] // 防止跨站请求伪造攻击 public async TaskIActionResult Create([Bind(Id,Title,Description,IsCompleted)] TaskItem taskItem) { if (ModelState.IsValid) // 检查数据注解验证是否通过 { taskItem.CreatedDate DateTime.Now; _context.Add(taskItem); await _context.SaveChangesAsync(); // 异步保存到数据库 return RedirectToAction(nameof(Index)); // 创建成功后跳转到列表页 } return View(taskItem); // 如果验证失败返回表单并显示错误信息 }Edit - 编辑任务// 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,CreatedDate)] 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); } private bool TaskItemExists(int id) { return _context.Tasks.Any(e e.Id id); }Delete 和 Details方法逻辑类似主要是根据 id 查询实体然后或删除、或展示。关键点异步编程大量使用async/await和ToListAsync(),SaveChangesAsync()。这是现代 Web 开发的标准做法能提高服务器吞吐量避免线程阻塞。模型绑定[Bind(...)]属性指定了哪些模型属性可以从请求中绑定这是一种安全措施防止过度发布攻击。模型验证ModelState.IsValid会检查模型上的数据注解我们稍后在 Model 上添加。这是保证数据有效性的第一道防线。PRG 模式Post-Redirect-Get。在 POST 请求处理成功后如 Create, Edit, Delete我们使用RedirectToAction跳转到一个 GET 请求的页面如 Index。这可以防止用户刷新页面时重复提交表单。3.3 为模型添加数据验证回到TaskItem.cs使用数据注解来添加简单的验证规则using System.ComponentModel.DataAnnotations; namespace TaskManager.Models { public class TaskItem { public int Id { get; set; } [Required(ErrorMessage 任务标题是必填项)] [StringLength(100, ErrorMessage 标题长度不能超过100个字符)] public string Title { get; set; } string.Empty; [Display(Name 任务描述)] public string? Description { get; set; } [Display(Name 是否完成)] public bool IsCompleted { get; set; } [Display(Name 创建时间)] [DataType(DataType.DateTime)] public DateTime CreatedDate { get; set; } DateTime.Now; } }[Required],[StringLength]等注解会在表单提交时被 MVC 框架自动验证并通过ModelState.IsValid反映结果。[Display]注解则用于在视图中生成更友好的字段标签。控制器作为交通指挥它不关心数据具体怎么存那是 DbContext 的事也不关心页面具体长什么样那是视图的事它只负责流程控制接收什么请求调用什么数据返回什么视图或结果。这种清晰的分离正是 MVC 模式的价值。4. 视图与前端呈现用 Bootstrap 快速搭建可用的 UI视图是 MVC 中的“V”负责将数据渲染成 HTML 页面。我们将使用 ASP.NET Core 的 Razor 语法和 Bootstrap 5 框架来构建界面。目标是创建与控制器 Action 对应的视图文件实现任务列表、创建表单、编辑表单等页面并利用 Bootstrap 使其美观且响应式。4.1 布局与全局样式首先我们有一个共享的布局文件Views/Shared/_Layout.cshtml。在创建 MVC 项目时这个文件可能不存在我们可以从 Razor Pages 模板的Pages/Shared/_Layout.cshtml复制过来或者手动创建。这里我们创建一个简化版并集成 Bootstrap。安装 Bootstrap最简单的方式是使用 LibMan库管理器。在项目根目录创建libman.json{ version: 1.0, defaultProvider: cdnjs, libraries: [ { library: bootstrap5.3.0, destination: wwwroot/lib/bootstrap/ }, { library: jquery3.7.1, destination: wwwroot/lib/jquery/ }, { library: jquery-validation1.19.5, destination: wwwroot/lib/jquery-validation/ }, { library: jquery-validation-unobtrusive4.0.0, destination: wwwroot/lib/jquery-validation-unobtrusive/ } ] }然后在命令行运行dotnet tool install -g Microsoft.Web.LibraryManager.Cli和libman restore或者直接在 Visual Studio 的“解决方案资源管理器”中右键点击libman.json选择“恢复客户端库”。创建_Layout.cshtml!DOCTYPE html html langen head meta charsetutf-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleViewData[Title] - 任务管理器/title link relstylesheet href~/lib/bootstrap/dist/css/bootstrap.min.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-actionIndex任务管理器/a button classnavbar-toggler typebutton>model IEnumerableTaskManager.Models.TaskItem { ViewData[Title] 任务列表; } h1任务列表/h1 p a asp-actionCreate classbtn btn-primary创建新任务/a /p table classtable table-striped table-hover thead tr thHtml.DisplayNameFor(model model.Title)/th thHtml.DisplayNameFor(model model.Description)/th thHtml.DisplayNameFor(model model.IsCompleted)/th thHtml.DisplayNameFor(model model.CreatedDate)/th th操作/th /tr /thead tbody foreach (var item in Model) { tr tdHtml.DisplayFor(modelItem item.Title)/td tdHtml.DisplayFor(modelItem item.Description)/td td input classform-check-input typecheckbox disabled (item.IsCompleted ? checked : ) /td tdHtml.DisplayFor(modelItem item.CreatedDate)/td td a asp-actionEdit asp-route-iditem.Id classbtn btn-sm btn-outline-primary编辑/a a asp-actionDetails asp-route-iditem.Id classbtn btn-sm btn-outline-info详情/a a asp-actionDelete asp-route-iditem.Id classbtn btn-sm btn-outline-danger删除/a /td /tr } /tbody /tablemodel IEnumerableTaskManager.Models.TaskItem指定此视图的模型类型是TaskItem的集合这与控制器IndexAction 中return View(tasks);传递的类型一致。Html.DisplayNameFor和Html.DisplayFor是 HTML Helper它们会使用 Model 上定义的[Display]注解来显示字段名和值更规范。asp-route-iditem.Id用于在链接中传递参数如任务的 Id。4.3 创建任务表单视图 (Create.cshtml 和 Edit.cshtml)这两个视图非常相似都是用来展示和提交表单的。我们以Create.cshtml为例model TaskManager.Models.TaskItem { ViewData[Title] 创建任务; } h1创建新任务/h1 hr / div classrow div classcol-md-4 form asp-actionCreate div asp-validation-summaryModelOnly classtext-danger/div 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/textarea span asp-validation-forDescription classtext-danger/span /div div classform-group form-check mb-3 label classform-check-label input classform-check-input asp-forIsCompleted / Html.DisplayNameFor(model model.IsCompleted) /label /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);} }这是整个 MVC 数据流闭环的关键视图表单标签form asp-actionCreate会生成一个action指向/Tasks/Create的 POST 表单。输入标签input asp-forTitle是 Tag Helper它会根据TaskItem模型的Title属性生成具有正确id,name和value的 HTML 输入框。name属性必须与控制器 Action 参数[Bind]列表中的属性名匹配模型绑定才能成功。验证标签span asp-validation-forTitle用于显示该字段的验证错误信息。div asp-validation-summaryModelOnly用于显示模型级别的错误。验证脚本section Scripts引入了 jQuery 验证脚本实现了客户端验证。用户在提交前就能看到错误提示体验更好。服务端验证ModelState.IsValid仍然是最终保障。Edit.cshtml视图几乎相同只是form的asp-action变为Edit并且通常需要一个隐藏域input typehidden asp-forId /来传递主键。4.4 运行与调试现在所有部件都已就位。在命令行运行dotnet run或从 IDE 启动项目。浏览器打开https://localhost:5001具体端口看控制台输出点击导航栏的“任务列表”和“新建任务”尝试创建、编辑、删除任务。你可能遇到的典型问题及排查思路404 错误检查Program.cs中的默认路由{controllerHome}/{actionIndex}/{id?}。访问/Tasks时会匹配到TasksController.Index()。数据库连接错误检查appsettings.json中的连接字符串特别是(localdb)\\mssqllocaldb的转义和实例名。查看输出窗口或日志看是否有详细的 SQL 异常。迁移未应用确保执行了dotnet ef database update。检查数据库TaskManagerDB和表Tasks是否已创建。视图找不到确保视图文件.cshtml放在正确的Views/[ControllerName]文件夹下且文件名与 Action 名一致Index.cshtml,Create.cshtml。5. 从“跑通”到“可用”全栈思维的深化与工程化考量一个能运行的项目只是一个开始。要让这个“玩具”项目具备“可用”的雏形我们需要思考几个更深层的问题这恰恰是全栈开发者与功能实现者的分水岭。5.1 理解数据流与职责分离回顾我们构建的整个流程用户在浏览器点击“新建任务”/Tasks/CreateGET。MVC 路由将请求路由到TasksController.Create()GET 方法。控制器执行方法返回Create.cshtml视图。视图引擎渲染视图生成包含空表单的 HTML 返回给浏览器。用户填写表单并提交/Tasks/CreatePOST。模型绑定器将表单数据绑定到TaskItem对象。控制器再次执行Create()POST 方法进行模型验证通过后调用_context.Add()和SaveChangesAsync()。EF Core将TaskItem对象的状态变化翻译成 SQLINSERT语句通过 ADO.NET 发送给SQL Server。SQL Server执行插入返回结果。控制器收到成功结果后发出RedirectToAction(Index)指令HTTP 302。浏览器重定向到/Tasks/Index开始新一轮的请求-响应循环展示更新后的列表。每一层各司其职视图 (View)只负责展示和收集数据。不包含业务逻辑。控制器 (Controller)协调者。接收请求调用业务逻辑本例中直接用了 DbContext更复杂的项目会有 Service 层决定返回什么响应视图、JSON、重定向。模型 (Model)包含业务数据实体类和业务规则验证注解。EF Core (ORM)数据访问抽象层。将对象操作转换为 SQL。SQL Server (Database)数据的持久化存储。理解这个闭环你就理解了 MVC 和全栈协作的基本原理。5.2 引入服务层解耦控制器与数据访问在当前的TasksController中我们直接使用了AppDbContext。对于小型应用这没问题但随着业务复杂控制器会变得臃肿且难以进行单元测试因为控制器与数据库紧耦合。更佳实践是引入一个服务层 (Service Layer)。创建服务接口与实现 在项目根目录创建Services文件夹添加ITaskService.cs和TaskService.cs。// ITaskService.cs using TaskManager.Models; namespace TaskManager.Services { public interface ITaskService { TaskIEnumerableTaskItem GetAllTasksAsync(); TaskTaskItem? GetTaskByIdAsync(int id); Task CreateTaskAsync(TaskItem taskItem); Task UpdateTaskAsync(TaskItem taskItem); Task DeleteTaskAsync(int id); } } // TaskService.cs using Microsoft.EntityFrameworkCore; using TaskManager.Models; namespace TaskManager.Services { public class TaskService : ITaskService { private readonly AppDbContext _context; public TaskService(AppDbContext context) { _context context; } public async TaskIEnumerableTaskItem GetAllTasksAsync() { return await _context.Tasks.OrderByDescending(t t.CreatedDate).ToListAsync(); } // 实现其他接口方法... } }在Program.cs中注册服务builder.Services.AddScopedITaskService, TaskService();修改控制器注入服务public class TasksController : Controller { private readonly ITaskService _taskService; public TasksController(ITaskService taskService) { _taskService taskService; } // Action 方法改为调用 _taskService public async TaskIActionResult Index() { var tasks await _taskService.GetAllTasksAsync(); return View(tasks); } }这样做的好处单一职责控制器只关注 HTTP 和视图服务类关注业务逻辑。可测试性可以轻松为服务类编写单元测试或用 Mock 服务测试控制器。可维护性数据访问逻辑变化时只需修改服务类不影响控制器。5.3 前端交互增强使用 AJAX 提升体验目前每次操作创建、编辑、删除都会导致页面完全刷新。我们可以用 jQuery 或 Fetch API 配合部分 Action 实现无刷新操作。例如实现一个异步删除在TasksController中添加一个返回 JSON 的 Action[HttpDelete] public async TaskIActionResult DeleteConfirmed(int id) { var taskItem await _context.Tasks.FindAsync(id); if (taskItem null) { return Json(new { success false, message 任务未找到。 }); } _context.Tasks.Remove(taskItem); await _context.SaveChangesAsync(); return Json(new { success true, message 删除成功。 }); }在Index.cshtml的删除按钮上绑定点击事件发送 AJAX 请求并根据结果更新 DOM。这引入了前后端分离的雏形后端提供 API前端负责交互和渲染。这也是现代 Web 开发的一种常见模式。5.4 部署与后续方向要让这个本地应用变成真正的“全栈”应用你还需要考虑部署可以将应用发布到 Azure App Service、Linux 服务器使用 Nginx 反向代理或 Docker 容器。数据库也需要部署到云数据库如 Azure SQL Database或服务器上的 SQL Server。安全性添加用户认证ASP.NET Core Identity、授权、防跨站脚本XSS和跨站请求伪造CSRF保护我们已用了[ValidateAntiForgeryToken]。性能对于大量数据Index页面的ToListAsync()可能成为瓶颈需要考虑分页Skip()和Take()。日志与监控使用ILogger接口记录日志集成 Application Insights 等监控工具。从“跑通”到“可用”再到“健壮”和“高效”每一步都需要你在理解当前技术栈的基础上不断引入新的工程化实践。这套C# .NET ASP.NET Core MVC EF Core SQL Server的组合为你提供了一个坚实、现代且生态丰富的起点。它不仅仅是五个技术的堆砌而是一个完整的、可演进的 Web 应用开发生态。当你理解了数据如何从表单流向数据库再如何从数据库流回页面你就掌握了全栈开发最核心的脉络。接下来就是沿着这条脉络去填充更复杂的业务逻辑、更优美的前端组件和更稳固的架构设计了。
返回列表