diff --git "a/\351\231\210\346\201\251\347\224\237/20251229-\346\220\255\345\273\272MVC\351\241\271\347\233\256.md" "b/\351\231\210\346\201\251\347\224\237/20251229-\346\220\255\345\273\272MVC\351\241\271\347\233\256.md" new file mode 100644 index 0000000000000000000000000000000000000000..edaec3186b7dc118899f18603b69582fc512d3ca --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20251229-\346\220\255\345\273\272MVC\351\241\271\347\233\256.md" @@ -0,0 +1,608 @@ +# ** 第一章:搭建开发环境与第一个MVC项目** + +## **章节目标** + +- 理解ASP.NET Core MVC的基本概念和架构 +- 成功搭建VSCode开发环境并创建第一个MVC项目 +- 了解MVC项目的基本结构,能够使用命令行和VSCode运行项目 + +## **核心任务** + +使用VSCode和.NET 8 SDK创建第一个ASP.NET Core MVC项目,运行后显示"欢迎来到学生管理系统"的欢迎页面。 + +------ + +## **1. 任务引入:我们要做什么?** + +想象一下,你要为学校开发一个"学生信息管理系统"。今天我们要迈出第一步:搭建轻量级开发环境,创建一个基本的Web应用程序框架。我们将使用VSCode这个轻量但强大的编辑器,配合.NET命令行工具来完成所有操作。 + +**最终效果预览**: ![项目运行效果](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/project-run.svg) + +------ + +## **2. 知识点学习** + +### **知识点1:什么是ASP.NET Core MVC?** + +#### **1.1 ASP.NET Core 是什么?** + +- **跨平台框架**:可以在Windows、Linux、macOS上运行 +- **高性能**:比传统ASP.NET更快 +- **开源**:完全免费,社区活跃 +- **模块化**:只包含需要的组件,减少应用体积 +- **.NET 8**:最新的长期支持版本,性能更好,功能更丰富 + +**比喻理解**: + +> ASP.NET Core就像一辆汽车的**底盘和发动机**,它提供了Web应用运行的基础能力。 + +![ASP.NET Core架构图](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/aspnet-arch.svg) + +#### **1.2 MVC模式是什么?** + +MVC是**Model-View-Controller**的缩写,是一种软件设计模式。但在本课程中,我们将按照**C→V→M**的顺序学习: + +1. **Controller(控制器)**:先学这个!处理用户请求的"服务员" + - 接收用户请求 + - 协调模型和视图 + - 返回响应 +2. **View(视图)**:然后学这个!展示数据的"网页设计师" + - 决定页面长什么样 + - 使用Razor语法显示数据 + - 生成HTML返回给浏览器 +3. **Model(模型)**:最后学这个!存储数据的"数据库管理员" + - 定义数据结构 + - 处理业务逻辑 + - 与数据库交互 + +![MVC流程图](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/mvc-flow.svg) + +**工作流程**: + +1. 用户在浏览器输入网址(发送请求) +2. **Controller** 接收请求 +3. **Controller** 调用 **Model** 获取数据 +4. **Model** 返回数据给 **Controller** +5. **Controller** 选择 **View** 并传递数据 +6. **View** 渲染HTML页面返回给用户 + +------ + +### **知识点2:VSCode开发环境配置** + +#### **2.1 需要安装的软件** + +| 软件 | 作用 | 下载地址 | +| ---------------------- | ------------------------------ | ------------------------------------------------------------ | +| **.NET 8.0 SDK** | .NET开发工具包(必须首先安装) | [dotnet.microsoft.com](https://gitee.com/link?target=https%3A%2F%2Fdotnet.microsoft.com%2F) | +| **Visual Studio Code** | 轻量级代码编辑器 | [code.visualstudio.com](https://gitee.com/link?target=https%3A%2F%2Fcode.visualstudio.com%2F) | +| **C#扩展** | VSCode的C#语言支持 | 在VSCode扩展商店中搜索"C#" | + +#### **2.2 安装步骤** + +**步骤1:安装.NET 8 SDK** + +1. 访问下载页面,选择你的操作系统 +2. 下载并运行安装程序 +3. 安装完成后,打开终端验证: + +``` +dotnet --version +``` + +应该显示 `8.0.x` 版本号 + +**步骤2:安装Visual Studio Code** + +1. 下载VSCode安装包 +2. 按照向导完成安装 +3. 启动VSCode + +**步骤3:安装必要扩展** + +1. 打开VSCode,点击左侧扩展图标(或按Ctrl+Shift+X) +2. 搜索并安装以下扩展: + - **C#** (由Microsoft提供) + - **C# Dev Kit** (可选,但推荐) + - **SQLite Viewer** (用于查看数据库) + - **Auto-Using for C#** (自动添加using语句) + +![VSCode扩展安装](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/vscode-extensions.svg) + +------ + +### **知识点3:使用命令行创建MVC项目** + +#### **3.1 为什么使用命令行?** + +- **更灵活**:可以在任何目录创建项目 +- **更透明**:了解项目创建的每一个步骤 +- **技能通用**:命令行技能在其他开发中也会用到 + +#### **3.2 创建项目步骤** + +**步骤1:打开终端** + +- Windows: 按Win+R,输入`cmd`或使用PowerShell +- Mac/Linux: 打开Terminal + +**步骤2:创建项目目录并进入** + +``` +mkdir StudentManagementSystem +cd StudentManagementSystem +``` + +**步骤3:创建MVC项目** + +``` +dotnet new mvc -n StudentManagementSystem +``` + +**步骤4:用VSCode打开项目** + +``` +code . +``` + +#### **3.3 项目结构解析** + +项目创建成功后,在VSCode中查看项目结构: + +``` +StudentManagementSystem/ +│ +├── Properties/ +│ └── launchSettings.json # 项目启动配置 +│ +├── wwwroot/ # 静态资源文件夹(CSS、JS、图片) +│ ├── css/ +│ ├── js/ +│ └── lib/ # Bootstrap、jQuery等库 +│ +├── Controllers/ # 控制器文件夹(先学这个!) +│ └── HomeController.cs # 默认的Home控制器 +│ +├── Views/ # 视图文件夹(然后学这个!) +│ ├── Home/ # Home控制器对应的视图 +│ │ ├── Index.cshtml # 首页视图 +│ │ └── Privacy.cshtml # 隐私页视图 +│ ├── Shared/ # 共享视图 +│ │ ├── _Layout.cshtml # 布局页(母版页) +│ │ └── _ValidationScriptsPartial.cshtml +│ └── _ViewStart.cshtml # 视图启动文件 +│ +├── Models/ # 模型文件夹(最后学这个!) +│ └── (暂时为空) +│ +├── Program.cs # 程序入口(ASP.NET Core 6+) +├── appsettings.json # 应用程序配置 +└── StudentManagementSystem.csproj # 项目文件 +``` + +**重要文件说明**: + +1. **Program.cs** - 应用程序的入口点(ASP.NET Core 6+的简化模板) + +``` +var builder = WebApplication.CreateBuilder(args); + +// 添加服务到容器 +builder.Services.AddControllersWithViews(); // 注册MVC服务 + +var app = builder.Build(); + +// 配置HTTP请求管道 +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Home/Error"); + app.UseHsts(); // 使用HTTP严格传输安全协议 +} + +app.UseHttpsRedirection(); // 重定向HTTP到HTTPS +app.UseStaticFiles(); // 启用静态文件服务(wwwroot文件夹) +app.UseRouting(); // 启用路由 +app.UseAuthorization(); // 启用授权 + +// 配置默认路由 +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); // 默认访问Home/Index + +app.Run(); // 运行应用 +``` + +1. **HomeController.cs** - 第一个控制器(下一章重点学习) + +``` +using Microsoft.AspNetCore.Mvc; + +namespace StudentManagementSystem.Controllers +{ + public class HomeController : Controller // 继承Controller基类 + { + private readonly ILogger _logger; + + public HomeController(ILogger logger) + { + _logger = logger; + } + + // 动作方法:处理首页请求 + public IActionResult Index() + { + return View(); // 返回Views/Home/Index.cshtml + } + + // 动作方法:处理隐私页请求 + public IActionResult Privacy() + { + return View(); // 返回Views/Home/Privacy.cshtml + } + } +} +``` + +------ + +### **知识点4:在VSCode中运行与调试** + +#### **4.1 运行项目** + +在VSCode中有多种方式运行项目: + +**方式1:使用命令行** + +``` +dotnet run +``` + +程序启动后,按Ctrl+点击终端中的链接(如:[https://localhost:7126](https://gitee.com/link?target=https%3A%2F%2Flocalhost%3A7126)) + +**方式2:使用VSCode运行配置** + +1. 按F5或点击"运行和调试"侧边栏 +2. 选择".NET Core"环境 +3. VSCode会自动创建`.vscode/launch.json`配置文件 + +#### **4.2 VSCode调试技巧** + +- **设置断点**:在代码行号左侧点击,出现红点 +- **启动调试**:按F5 +- **单步执行**:F10(逐过程)、F11(逐语句) +- **查看变量**:鼠标悬停或查看"变量"面板 + +#### **4.3 项目运行流程** + +``` +dotnet run + ↓ +加载Program.cs → 配置服务 → 构建中间件管道 + ↓ +监听端口(如:5000, 5001) + ↓ +浏览器访问 https://localhost:5001 + ↓ +请求经过中间件管道 + ↓ +路由匹配到HomeController.Index() + ↓ +返回Views/Home/Index.cshtml + ↓ +浏览器显示页面 +``` + +------ + +## **3. 任务实施:修改欢迎页面** + +### **步骤1:找到并修改首页视图** + +1. 在VSCode中,打开 `Views/Home/Index.cshtml` +2. 将文件内容修改为: + +``` +@{ + ViewData["Title"] = "首页"; +} + +
+

欢迎来到学生管理系统

+

使用ASP.NET Core MVC + .NET 8 + VSCode构建

+ +
+

📚 本课程学习路径

+
+
+
+
+

第一章

+

搭建环境

+ 当前进度 +
+
+
+
+
+
+

第二章

+

控制器

+ 处理请求 +
+
+
+
+
+
+

第三章

+

视图

+ 展示页面 +
+
+
+
+
+
+

第四章

+

模型

+ 定义数据 +
+
+
+
+
+
+

第五-七章

+

CRUD

+ 完整功能 +
+
+
+
+ +
+
+
🛠️ 开发环境
+
    +
  • 编辑器: Visual Studio Code
  • +
  • 框架: .NET 8 SDK
  • +
  • 模式: MVC (控制器→视图→模型)
  • +
  • 数据库: SQLite (轻量,无需安装)
  • +
+
+
+ + +
+
+``` + +### **步骤2:运行项目查看效果** + +1. 打开终端(Ctrl+`) +2. 输入命令: + +``` +dotnet run +``` + +1. 终端显示: + +``` +正在生成... +info: Microsoft.Hosting.Lifetime[14] + Now listening on: https://localhost:7126 +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://localhost:5256 +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. +``` + +1. 按Ctrl+点击 `https://localhost:7126` 链接 + +### **步骤3:查看运行效果** + +![修改后的首页](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/homepage-modified.svg) + +------ + +## **4. 动手练习** + +### **练习1:修改导航栏** + +打开 `Views/Shared/_Layout.cshtml`,找到导航栏部分,修改菜单项: + +``` + +``` + +### **练习2:更改页面标题** + +修改 `_Layout.cshtml` 中的 `` 标签: + +``` +<title>@ViewData["Title"] - 学生信息管理系统 (.NET 8) +``` + +### **练习3:体验命令行操作** + +在终端中尝试以下命令,观察结果: + +``` +# 查看可用的项目模板 +dotnet new list + +# 查看项目信息 +dotnet --info + +# 恢复NuGet包(如果缺少依赖) +dotnet restore + +# 清理生成文件 +dotnet clean + +# 发布项目(生成可部署文件) +dotnet publish -c Release +``` + +------ + +## **5. 常见问题解答** + +### **Q1:运行`dotnet run`时提示"No project found"?** + +**解决方案**: + +``` +# 确保在项目目录中(有.csproj文件的目录) +cd StudentManagementSystem + +# 或者指定项目文件 +dotnet run --project StudentManagementSystem.csproj +``` + +### **Q2:VSCode提示"找不到命名空间"?** + +**解决方案**: + +1. 确保安装了C#扩展 +2. 在终端运行:`dotnet restore` +3. 重启VSCode +4. 如果仍不行,检查`.csproj`文件中的包引用 + +### **Q3:端口被占用怎么办?** + +**解决方案**: + +1. 停止当前程序(在终端按Ctrl+C) +2. 修改 `Properties/launchSettings.json`: + +``` +"applicationUrl": "https://localhost:5001;http://localhost:5000" +``` + +1. 或者使用指定端口运行: + +``` +dotnet run --urls "https://localhost:6000;http://localhost:6001" +``` + +### **Q4:如何查看项目依赖的NuGet包?** + +``` +# 查看项目引用的包 +dotnet list package + +# 添加新包(后续会用到) +dotnet add package Microsoft.EntityFrameworkCore.Sqlite +``` + +------ + +## **6. 章节总结** + +| 学习要点 | 掌握程度 | 检查点 | +| ---------------- | ------------------ | -------------------------------------- | +| ✅ .NET 8 SDK安装 | 能独立安装和验证 | `dotnet --version` 显示8.0.x | +| ✅ VSCode环境配置 | 会安装必要扩展 | C#扩展已安装,能识别.cs文件 | +| ✅ 命令行创建项目 | 熟练使用dotnet CLI | 能用 `dotnet new mvc` 创建项目 | +| ✅ 项目结构理解 | 知道主要文件夹作用 | 能说出Controllers、Views、Models的作用 | +| ✅ VSCode运行调试 | 会运行和查看项目 | 能用 `dotnet run` 启动项目并访问 | +| ✅ 修改视图页面 | 能修改HTML/CSS | 成功修改了欢迎页面内容 | + +------ + +## **7. 预习提示** + +下一章我们将学习: + +- **控制器(Controller)的核心作用** +- **创建第一个控制器类** +- **动作方法(Action Method)的使用** +- **路由的基本概念** + +**思考题**: + +> 当用户访问 `https://localhost:5001/Student` 时,程序如何知道调用哪个控制器的哪个方法? + +**提前准备**: + +1. 在VSCode中打开当前项目 +2. 查看 `Controllers/HomeController.cs` 文件结构 +3. 尝试创建一个新的文本文件,重命名为 `TestController.cs` + +------ + +## **教师教学提示** + +### **课堂时间安排建议**(90分钟课堂) + +- **环境检查与准备**:15分钟(确保所有学生环境正常) +- **知识点讲解与演示**:25分钟 +- **学生动手操作**:30分钟(跟随步骤创建项目) +- **问题解答与练习**:15分钟 +- **总结与预习**:5分钟 + +### **重点强调** + +1. **环境配置是关键**:确保每个学生都能成功运行`dotnet --version` +2. **命令行技能重要**:鼓励学生使用命令行而非完全依赖GUI +3. **MVC顺序说明**:解释为什么先教控制器(更快看到交互效果) +4. **错误处理能力**:教学生如何阅读错误信息并解决 + +### **课堂练习建议** + +1. **分组竞赛**:看哪组最先成功运行项目 +2. **错误重现**:故意制造常见错误(如端口占用),让学生解决 +3. **扩展探索**:让学生尝试创建其他类型项目(如console, webapi) + +### **扩展思考(供学有余力的学生)** + +1. 研究 `dotnet new` 的其他模板类型 +2. 了解 `Program.cs` 中每个中间件的作用 +3. 尝试修改 `appsettings.json` 中的日志级别 +4. 研究如何同时运行多个项目 + +------ + +**任务完成标志**: + +- 学生能够使用命令行创建MVC项目 +- 项目能成功运行并显示自定义欢迎页面 +- 学生理解项目基本结构,特别是Controllers文件夹的重要性 +- 学生能说出控制器在MVC中的核心作用 + +------ + +**下一章预告**:第二章将创建我们自己的 `StudentController`,开始处理真正的业务逻辑! + +------ + +✅ **本章完成** | 下一章:[控制器(Controller)- 应用的指挥中心] \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20251231--\346\216\247\345\210\266\345\231\250.md" "b/\351\231\210\346\201\251\347\224\237/20251231--\346\216\247\345\210\266\345\231\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..83c188a42f1436578bc4bc63507ea77f9eeafb09 --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20251231--\346\216\247\345\210\266\345\231\250.md" @@ -0,0 +1,139 @@ +# ** 第二章:控制器(Controller) - 应用的指挥中心** + +## **章节目标** + +- 理解控制器在MVC架构中的核心作用 +- 能够创建自定义控制器并添加动作方法 +- 掌握从控制器向视图传递数据的三种方式 +- 理解路由的基本概念和配置方式 + +## **核心任务** + +创建 `StudentController`,添加 `Index` 动作方法,使用模拟学生数据,并通过视图展示学生列表。 + +------ + +## **1. 任务引入:我们要做什么?** + +在第一章中,我们创建了项目框架并修改了欢迎页面。现在我们要开始真正的业务逻辑开发!我们将创建一个专门管理学生信息的控制器,并让它显示学生列表。 + +**任务分解**: + +1. 创建 `StudentController` 控制器 +2. 在控制器中创建 `Index` 动作方法 +3. 创建模拟的学生数据列表 +4. 将数据传递给视图进行显示 + +**最终效果预览**: ![学生列表页面](https://gitee.com/myhfw003/aspnetcore-mvc-course-grade24/raw/master/assets/images/student-list.svg) + +------ + +## **2. 知识点学习** + +### **知识点1:控制器(Controller)的作用** + +#### **1.1 控制器是什么?** + +控制器是MVC模式的"大脑"或"指挥中心",负责: + +- 接收用户的HTTP请求 +- 处理业务逻辑 +- 调用模型获取数据 +- 选择合适的视图 +- 将数据传递给视图 + +**比喻理解**: + +> 控制器就像**餐厅的服务员**: +> +> 1. 接收顾客点单(用户请求) +> 2. 通知厨房做菜(调用模型) +> 3. 把做好的菜端给顾客(返回视图和数据) + +#### **1.2 控制器的命名规范** + +- 名称必须以 `Controller` 结尾(如 `StudentController`) +- 通常放在 `Controllers` 文件夹中 +- 继承 `Microsoft.AspNetCore.Mvc.Controller` 类 + +``` +// 正确的命名 +public class StudentController : Controller + +// 错误的命名(不会自动识别为控制器) +public class StudentManager : Controller +``` + +#### **1.3 控制器的生命周期** + +``` +HTTP请求 → 路由系统 → 找到对应控制器 → 创建控制器实例 → +调用动作方法 → 返回结果 → 销毁控制器实例 +``` + +### **知识点2:创建控制器与动作方法** + +#### **2.1 什么是动作方法(Action Method)?** + +- 控制器中的公共方法(public method) +- 通常返回 `IActionResult` 或其派生类型 +- 每个动作方法对应一个用户可访问的URL + +``` +public class StudentController : Controller +{ + // 动作方法:显示学生列表 + public IActionResult Index() + { + return View(); // 返回视图 + } + + // 动作方法:显示学生详情 + public IActionResult Details(int id) + { + // 处理逻辑 + return View(); + } +} +``` + +#### **2.2 动作方法的返回类型** + +| 返回类型 | 作用 | 示例 | +| ---------------- | --------------- | ---------------------------------- | +| `ViewResult` | 返回视图 | `return View();` | +| `JsonResult` | 返回JSON数据 | `return Json(data);` | +| `ContentResult` | 返回纯文本 | `return Content("Hello");` | +| `RedirectResult` | 重定向到其他URL | `return Redirect("/Home");` | +| `FileResult` | 返回文件 | `return File(bytes, "image/png");` | + +#### **2.3 创建控制器的两种方式** + +**方式1:使用VSCode手动创建** + +1. 在 `Controllers` 文件夹右键 → 新建文件 +2. 命名为 `StudentController.cs` +3. 输入控制器代码 + +**方式2:使用命令行工具** + +``` +# 在项目根目录运行 +dotnet aspnet-codegenerator controller -name StudentController -m Student -dc ApplicationDbContext --relativeFolderPath Controllers --useDefaultLayout --referenceScriptLibraries +``` + +#### **2.4 为控制器添加依赖注入** + +控制器可以通过构造函数接收依赖项: + +``` +public class StudentController : Controller +{ + private readonly ILogger _logger; + + // 依赖注入:框架自动提供ILogger实例 + public StudentController(ILogger logger) + { + _logger = logger; + _logger.LogInformation("StudentController created"); +``` \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20260104-\346\216\247\345\210\266\345\231\250\350\267\257\347\224\261.md" "b/\351\231\210\346\201\251\347\224\237/20260104-\346\216\247\345\210\266\345\231\250\350\267\257\347\224\261.md" new file mode 100644 index 0000000000000000000000000000000000000000..241ac11f1c632fb79c1a5ff46624021ce8b4c8d2 --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20260104-\346\216\247\345\210\266\345\231\250\350\267\257\347\224\261.md" @@ -0,0 +1,898 @@ +#### **3.1 三种传递数据的方式** + +**方式1:ViewData - 弱类型字典** + +- 使用 `ViewData` 字典 +- 键是字符串,值是object类型 +- 需要类型转换 + +``` +public IActionResult Index() +{ + ViewData["Title"] = "学生列表"; + ViewData["Count"] = 25; + return View(); +} +``` + +在视图中使用: + +``` +

@ViewData["Title"]

+

学生总数: @ViewData["Count"]

+``` + +**方式2:ViewBag - 动态类型** + +- `ViewBag` 是动态对象 +- 不需要类型转换 +- 实际上是 `ViewData` 的包装器 + +``` +public IActionResult Index() +{ + ViewBag.Title = "学生列表"; + ViewBag.Count = 25; + ViewBag.CurrentDate = DateTime.Now; + return View(); +} +``` + +在视图中使用: + +``` +

@ViewBag.Title

+

当前时间: @ViewBag.CurrentDate.ToString("yyyy-MM-dd")

+``` + +**方式3:强类型模型(推荐)** + +- 创建模型类 +- 将模型实例传递给视图 +- 类型安全,智能提示支持 + +``` +public IActionResult Index() +{ + var students = new List + { + new Student { Id = 1, Name = "张三", Age = 20 }, + new Student { Id = 2, Name = "李四", Age = 21 } + }; + + return View(students); // 传递模型给视图 +} +``` + +在视图中使用(需要声明模型类型): + +``` +@model List + +

学生列表

+@foreach(var student in Model) +{ +

@student.Name - @student.Age 岁

+} +``` + +#### **3.2 三种方式的对比** + +| 特性 | ViewData | ViewBag | 强类型模型 | +| ---------- | -------------- | -------------- | ------------ | +| 类型安全 | ❌ 需要类型转换 | ❌ 运行时检查 | ✅ 编译时检查 | +| 智能提示 | ❌ 无 | ❌ 无 | ✅ 有 | +| 性能 | ✅ 较快 | ⚠️ 稍慢(动态) | ✅ 快 | +| 代码可读性 | ⚠️ 一般 | ⚠️ 一般 | ✅ 好 | +| 推荐场景 | 少量简单数据 | 少量简单数据 | 复杂数据结构 | + +### **知识点4:路由(Routing)基础** + +#### **4.1 什么是路由?** + +路由是将URL映射到控制器的规则系统。 + +**默认路由规则**(在 `Program.cs` 中配置): + +``` +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); +``` + +**路由模板解释**: + +- `{controller}`:控制器名(去掉Controller后缀) +- `{action}`:动作方法名 +- `{id?}`:可选参数,`?` 表示可选 + +#### **4.2 URL到控制器的映射示例** + +| URL | 映射结果 | +| -------------------- | -------------------------------- | +| `/` | HomeController.Index() | +| `/Home` | HomeController.Index() | +| `/Home/Privacy` | HomeController.Privacy() | +| `/Student` | StudentController.Index() | +| `/Student/Details/5` | StudentController.Details(id: 5) | +| `/Student/Edit/3` | StudentController.Edit(id: 3) | + +#### **4.3 自定义路由特性** + +可以在控制器或动作方法上使用 `[Route]` 特性: + +``` +[Route("api/students")] // 自定义路由 +public class StudentController : Controller +{ + [Route("")] // 对应 /api/students + public IActionResult Index() { ... } + + [Route("{id:int}")] // 对应 /api/students/5 + public IActionResult Details(int id) { ... } + + [Route("add")] // 对应 /api/students/add + public IActionResult Create() { ... } +} +``` + +#### **4.4 路由约束** + +限制参数的类型和格式: + +``` +[Route("students/{id:int:min(1)}")] // id必须是大于0的整数 +public IActionResult Details(int id) { ... } + +[Route("students/{name:alpha}")] // name只能是字母 +public IActionResult Search(string name) { ... } +``` + +------ + +## **3. 任务实施:创建学生控制器** + +### **步骤1:创建学生模型类(临时)** + +在正式学习模型之前,我们先创建一个简单的临时模型: + +1. 在 `Models` 文件夹中创建 `Student.cs` 文件 +2. 添加以下代码: + +``` +namespace StudentManagementSystem.Models +{ + public class Student + { + public int Id { get; set; } + public string? Name { get; set; } + public int Age { get; set; } + public string? Email { get; set; } + public DateTime EnrollmentDate { get; set; } + public string? Major { get; set; } + } +} +``` + +### **步骤2:创建StudentController** + +1. 在 `Controllers` 文件夹中创建 `StudentController.cs` +2. 添加以下代码: + +``` +using Microsoft.AspNetCore.Mvc; +using StudentManagementSystem.Models; +using System.Diagnostics; + +namespace StudentManagementSystem.Controllers +{ + public class StudentController : Controller + { + // 模拟学生数据(临时,后续会从数据库获取) + private readonly List _students = new List + { + new Student { Id = 1, Name = "张三", Age = 20, Email = "zhangsan@example.com", + EnrollmentDate = new DateTime(2023, 9, 1), Major = "计算机科学" }, + new Student { Id = 2, Name = "李四", Age = 21, Email = "lisi@example.com", + EnrollmentDate = new DateTime(2023, 9, 1), Major = "软件工程" }, + new Student { Id = 3, Name = "王五", Age = 19, Email = "wangwu@example.com", + EnrollmentDate = new DateTime(2024, 3, 1), Major = "网络工程" }, + new Student { Id = 4, Name = "赵六", Age = 22, Email = "zhaoliu@example.com", + EnrollmentDate = new DateTime(2022, 9, 1), Major = "数据科学" }, + new Student { Id = 5, Name = "钱七", Age = 20, Email = "qianqi@example.com", + EnrollmentDate = new DateTime(2023, 9, 1), Major = "人工智能" } + }; + + // GET: /Student 或 /Student/Index + public IActionResult Index() + { + // 使用ViewBag传递额外信息 + ViewBag.PageTitle = "学生信息管理系统"; + ViewBag.LastUpdated = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + ViewBag.TotalStudents = _students.Count; + + // 使用强类型模型传递主要数据 + return View(_students); + } + + // GET: /Student/Details/5 + public IActionResult Details(int id) + { + // 根据ID查找学生 + var student = _students.FirstOrDefault(s => s.Id == id); + + if (student == null) + { + // 使用ViewData传递错误信息 + ViewData["ErrorMessage"] = $"未找到ID为 {id} 的学生信息"; + return View("Error"); + } + + return View(student); + } + + // GET: /Student/Create + public IActionResult Create() + { + ViewBag.Action = "添加新学生"; + return View(); + } + + // POST: /Student/Create + [HttpPost] // 只处理POST请求 + public IActionResult Create(Student student) + { + // 这里暂时只是演示,实际应该保存到数据库 + if (ModelState.IsValid) + { + // 模拟添加新学生(设置ID为最大值+1) + student.Id = _students.Max(s => s.Id) + 1; + _students.Add(student); + + // 重定向到列表页 + return RedirectToAction(nameof(Index)); + } + + // 验证失败,重新显示表单 + ViewBag.Action = "添加新学生"; + return View(student); + } + + // 显示错误页面 + [Route("Student/Error")] + public IActionResult Error() + { + return View(); + } + } +} +``` + +### **步骤3:创建对应的视图文件夹和文件** + +1. 创建 `Views/Student` 文件夹 + +2. 在 + + + + ``` + Views/Student + ``` + + + + 中创建以下文件: + + - `Index.cshtml`(学生列表) + - `Details.cshtml`(学生详情) + - `Create.cshtml`(添加学生) + - `Error.cshtml`(错误页面) + +### **步骤4:创建学生列表视图** + +编辑 `Views/Student/Index.cshtml`: + +``` +@model List + +@{ + ViewData["Title"] = "学生列表"; +} + +
+
+
+

@ViewBag.PageTitle

+

最后更新: @ViewBag.LastUpdated | 学生总数: @ViewBag.TotalStudents

+
+ + 添加新学生 + +
+ + @if (Model != null && Model.Any()) + { +
+ + + + + + + + + + + + + + @foreach (var student in Model) + { + + + + + + + + + + } + +
学号姓名年龄专业邮箱入学时间操作
@student.Id.ToString("D3")@student.Name@student.Age + @student.Major + + + @student.Email + + @student.EnrollmentDate.ToString("yyyy-MM-dd") +
+ + 详情 + + + +
+
+
+ } + else + { + + } + +
+
+
📊 数据统计
+
+
+
+
+
+

@ViewBag.TotalStudents

+

学生总数

+
+
+
+
+

@(Model?.Average(s => s.Age)?.ToString("F1") ?? "0")

+

平均年龄

+
+
+
+
+

@(Model?.Where(s => s.Major == "计算机科学").Count() ?? 0)

+

计算机科学专业

+
+
+
+
+

@(Model?.Where(s => s.Age >= 21).Count() ?? 0)

+

21岁及以上

+
+
+
+
+
+
+ +@section Scripts { + +} +``` + +### **步骤5:创建其他视图** + +1. **创建详情视图** (`Views/Student/Details.cshtml`): + +``` +@model StudentManagementSystem.Models.Student + +@{ + ViewData["Title"] = "学生详情"; +} + +
+
+

学生详情

+ + 返回列表 + +
+ +
+
+
+
+
基本信息
+
+
+
+
学号:
+
@Model.Id.ToString("D3")
+ +
姓名:
+
@Model.Name
+ +
年龄:
+
@Model.Age 岁
+ +
邮箱:
+
+ + @Model.Email + +
+ +
专业:
+
+ @Model.Major +
+ +
入学时间:
+
@Model.EnrollmentDate.ToString("yyyy年MM月dd日")
+ +
在校时间:
+
+ @{ + var timeSpan = DateTime.Now - Model.EnrollmentDate; + var months = timeSpan.Days / 30; + } + @months 个月 +
+
+
+
+
+ +
+
+
+
快速操作
+
+
+
+ + + + 发送邮件 + + +
+
+
+ +
+
+
系统提示
+
+
+

+ 编辑和删除功能将在后续章节实现。 + 当前数据为模拟数据,重启应用后会重置。 +

+
+
+
+
+
+``` + +1. **创建添加学生视图** (`Views/Student/Create.cshtml`): + +``` +@model StudentManagementSystem.Models.Student + +@{ + ViewData["Title"] = ViewBag.Action ?? "添加学生"; +} + +
+
+
+
+
+

@ViewData["Title"]

+
+
+
+
+ + + +
+ +
+
+ + + +
+
+ + + +
+
+ +
+ + + +
+ +
+ + + +
+ +
+ + 取消 + + +
+
+
+
+ +
+
+
📝 填写说明
+
    +
  • 姓名为必填项,长度不超过50个字符
  • +
  • 年龄应在15-40岁之间
  • +
  • 邮箱需符合标准邮箱格式
  • +
  • 入学时间不能晚于当前日期
  • +
+
+
+
+
+
+ +@section Scripts { + +} +``` + +1. **创建错误视图** (`Views/Student/Error.cshtml`): + +``` +@{ + ViewData["Title"] = "错误"; +} + +
+
+
+
+
+

发生错误

+
+
+

@ViewData["ErrorMessage"]

+ +
+ +
+ +
+ + 返回学生列表 + + +
+
+
+
+
+
+``` + +### **步骤6:更新导航菜单** + +修改 `Views/Shared/_Layout.cshtml` 中的导航菜单,确保可以访问学生管理页面: + +找到导航菜单部分,添加或修改: + +``` + +``` + +### **步骤7:安装Bootstrap Icons** + +为了使用图标,我们需要添加Bootstrap Icons。在 `_Layout.cshtml` 的 `` 部分添加: + +``` + +``` + +### **步骤8:运行测试** + +1. 在终端中运行项目: + +``` +dotnet run +``` + +1. 访问以下URL测试功能: + - `https://localhost:7126/Student` - 学生列表 + - `https://localhost:7126/Student/Details/1` - 学生详情 + - `https://localhost:7126/Student/Create` - 添加学生 + - `https://localhost:7126/Student/Details/999` - 测试错误页面 + +------ + +## **4. 动手练习** + +### **练习1:创建教师控制器** + +1. 创建一个 `TeacherController` +2. 添加模拟教师数据(至少3条) +3. 实现 `Index` 动作显示教师列表 +4. 实现 `Details` 动作显示教师详情 +5. 创建对应的视图文件 + +### **练习2:添加搜索功能** + +在 `StudentController` 中添加搜索功能: + +1. 添加 `Search` 动作方法,接收 `keyword` 参数 +2. 根据关键字搜索学生姓名或专业 +3. 创建搜索表单和结果页面 + +### **练习3:实现分页功能** + +修改学生列表,添加分页: + +1. 添加 `page` 和 `pageSize` 参数 +2. 使用 `Skip()` 和 `Take()` 实现分页 +3. 在视图底部添加分页导航 + +### **练习4:添加API接口** + +创建返回JSON数据的API接口: + +1. 在 `StudentController` 中添加: + +``` +[Route("api/[controller]")] +public IActionResult GetStudents() +{ + return Json(_students); +} +``` + +1. 测试访问:`/api/student` + +------ + +## **5. 常见问题解答** + +### **Q1:访问 `/Student` 时出现404错误?** + +**可能原因**: + +1. 控制器命名错误(必须为 `StudentController`) +2. 控制器没有继承 `Controller` 类 +3. 没有 `Index` 动作方法 +4. 路由配置错误 + +**解决方案**: + +``` +# 检查程序启动日志 +dotnet run + +# 访问 /Student/Index 试试 +``` + +### **Q2:视图中显示 `@Model` 为null?** + +**可能原因**: + +1. 控制器没有传递模型给视图 +2. 视图顶部的 `@model` 声明不正确 + +**解决方案**: + +``` +// 确保传递了模型 +return View(students); // 不是 return View(); + +// 确保视图声明正确 +@model List // 不是 @model Student +``` + +### **Q3:为什么POST到 `/Student/Create` 无效?** + +**检查点**: + +1. 表单的 `method` 属性是否为 `post` +2. 控制器动作是否有 `[HttpPost]` 特性 +3. 表单字段的 `name` 属性是否与模型属性匹配 +4. 是否安装了模型验证所需的包 + +### **Q4:如何调试控制器代码?** + +**VSCode调试步骤**: + +1. 在控制器代码中设置断点(点击行号左侧) +2. 按F5启动调试 +3. 访问触发控制器的URL +4. 查看变量值,单步执行 + +------ + +## **6. 章节总结** + +| 学习要点 | 掌握程度 | 检查点 | +| -------------- | ------------------------- | -------------------------------------- | +| ✅ 控制器的作用 | 理解MVC中控制器的核心地位 | 能说明控制器在请求处理中的角色 | +| ✅ 创建控制器 | 能正确创建控制器类 | 成功创建StudentController并运行 | +| ✅ 动作方法 | 理解并创建动作方法 | 实现Index、Details、Create动作 | +| ✅ 数据传递 | 掌握三种传递方式 | 会使用ViewBag、ViewData和强类型模型 | +| ✅ 路由理解 | 理解URL到控制器的映射 | 能说明 `/Student/Details/1` 的映射过程 | +| ✅ 视图创建 | 创建与控制器对应的视图 | 创建了4个学生管理视图 | + +------ + +## **7. 预习提示** + +下一章我们将深入学习: + +- **Razor视图引擎**:在HTML中嵌入C#代码 +- **布局页和部分视图**:实现页面复用 +- **Tag Helpers**:简化HTML表单创建 +- **前端与后端交互**:完整的表单提交流程 + +**思考题**: + +> 当用户提交添加学生的表单时,数据是如何从浏览器传递到控制器,再保存到"数据库"的? + +**提前准备**: + +1. 查看 `Views/Student/Create.cshtml` 中的表单代码 +2. 研究表单字段是如何与 `Student` 模型属性绑定的 +3. 思考如何改进当前的学生数据存储方式 + +------ + +## **教师教学提示** + +### **课堂时间安排建议**(90分钟课堂) + +- **知识点讲解**:25分钟(重点:控制器角色、动作方法、数据传递) +- **代码演示**:15分钟(演示创建完整控制器流程) +- **学生动手操作**:30分钟(完成StudentController和视图) +- **练习与扩展**:15分钟(完成练习1-2) +- **总结答疑**:5分钟 + +### **重点强调** + +1. **控制器的桥梁作用**:强调控制器连接用户请求、模型数据和视图显示 +2. **动作方法对应URL**:让学生理解URL与控制器方法的对应关系 +3. **数据传递方式选择**:讲解三种方式的适用场景,强调强类型模型的优势 +4. **路由配置的重要性**:演示不同URL如何映射到不同控制器方法 + +### **教学难点突破** + +1. **依赖注入概念**:通过日志记录器示例简单介绍,第四章深入 +2. **模型绑定过程**:通过表单提交演示数据如何自动绑定到模型 +3. **HTTP方法区别**:通过GET/POST动作对比,解释RESTful设计 + +### **扩展活动建议** + +1. **代码审查**:分组展示各自的StudentController实现 +2. **Bug寻找比赛**:故意制造常见错误,让学生找出并修复 +3. **功能扩展挑战**:鼓励学生为控制器添加更多功能(排序、筛选等) + +------ + +**任务完成标志**: + +- 学生能够创建并访问 `/Student` 页面 +- 学生列表正确显示模拟数据 +- 详情页面能够根据ID显示对应学生信息 +- 添加学生表单能够提交并跳转回列表页 +- 学生理解控制器在MVC中的核心作用 \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20260105-mvc\346\250\241\345\274\217.md" "b/\351\231\210\346\201\251\347\224\237/20260105-mvc\346\250\241\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..81951e151e11e06c2c9537cccf1b8a50fec54cfc --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20260105-mvc\346\250\241\345\274\217.md" @@ -0,0 +1,32 @@ +# 笔记 +- mvc模式 +```bash +- 模型(Model):负责数据和业务逻辑,通常包含数据存储、检索和业务规则。 +- 视图(View):负责显示数据(模型)的用户界面,不包含业务逻辑。 +- 控制器(Controller):接收用户的输入,调用模型和视图去完成用户的请求。 +``` + +- 主要解决的问题 +```bash +解决了应用程序中业务逻辑、数据和界面显示的耦合问题,使得开发和维护更加清晰和简单。 +使用场景 +``` + +- 优点 +```bash +- 关注点分离:将数据、业务逻辑和界面显示分离,降低耦合度。 +- 易于维护:每个组件负责特定的任务,便于单独开发和维护。 +- 可扩展性:可以独立地替换或更新模型、视图或控制器。 +``` + + +-缺点 +```bash + +- 可能增加复杂性:对于简单项目,引入MVC可能会增加不必要的复杂性。 +- 性能问题:如果不正确使用,可能会导致性能问题。 + +``` + + +## 练习 \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20260107-MVC View.md" "b/\351\231\210\346\201\251\347\224\237/20260107-MVC View.md" new file mode 100644 index 0000000000000000000000000000000000000000..4752fce2fa6d7a9f552a6799c6187bdd554ccab6 --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20260107-MVC View.md" @@ -0,0 +1,114 @@ +# 笔记部分 + +## 一、MVC 中 View(视图)的核心概念 + +**MVC 是软件工程中经典的架构模式,分为 Model(模型)、View(视图)、Controller(控制器)三部分。其中:** + +- View(视图) 是用户直接看到并交互的界面,核心职责是展示数据和接收用户的交互操作,但不处理业务逻辑。 + +- 视图本身不包含业务逻辑,也不直接修改数据(Model),它只负责 “渲染” 从控制器 / 模型传递过来的数据,同时将用户的操作(比如点击按钮、输入内容)传递给控制器处理。 + +简单比喻:视图就像手机的屏幕和按键 —— 屏幕负责显示内容(比如微信聊天界面),按键 / 触屏接收你的操作(比如发消息),但真正处理 “发消息” 逻辑的是手机内部的程序(控制器 + 模型)。 + +## 二、视图的核心特点 + +- **被动性**:视图不会主动获取数据,而是由控制器 / 模型把数据 “喂” 给它,它只负责展示。 + +- **无逻辑**:视图不包含业务逻辑(比如计算、数据校验、数据库操作),仅保留少量 “展示相关的简单逻辑”(比如格式化时间、判断是否显示某个按钮)。 + +- **与模型解耦**:视图只依赖模型提供的数据接口,不关心模型的内部实现;即使模型修改,只要接口不变,视图无需改动。 + +## 三、实战示例(以 Python + Flask 为例) + +**Flask 是典型的 MVC 框架(Flask 中常称 View 为模板,Controller 为视图函数),下面用一个简单示例展示视图的作用:** + +### 1. 项目结构 + +```plaintext +my_mvc_app/ +├── app.py # 控制器(Controller)+ 模型(Model) +└── templates/ # 视图(View)目录 + └── user.html # 具体的视图模板 +``` + +### 2. 代码实现 + +#### (1)模型 + 控制器(app.py) + +```python +from flask import Flask, render_template + +app = Flask(__name__) + +# 模拟 Model(模型):存储/处理数据 +class UserModel: + def get_user_info(self, user_id): + # 模拟从数据库获取用户数据 + return { + "id": user_id, + "name": "张三", + "age": 25, + "email": "zhangsan@example.com" + } + +# 模拟 Controller(控制器):协调模型和视图 +@app.route('/user/') +def user_controller(user_id): + # 1. 调用模型获取数据 + user_model = UserModel() + user_data = user_model.get_user_info(user_id) + + # 2. 将数据传递给视图,让视图渲染 + return render_template('user.html', user=user_data) + +if __name__ == '__main__': + app.run(debug=True) +``` + +#### (2)视图(templates/user.html) + +```html + + + + + 用户信息 + + +

用户详情

+ +

ID:{{ user.id }}

+

姓名:{{ user.name }}

+

年龄:{{ user.age }}

+

邮箱:{{ user.email }}

+ + + 返回首页 + + +``` + +### 3. 代码解释 + +- **视图(user.html)** 完全不处理数据逻辑,只通过 {{ user.xxx }} 展示控制器传递的 user 数据; + +- 用户点击 “返回首页” 的操作,视图仅负责触发跳转,真正的逻辑(比如返回首页的处理)由控制器(app.py 中的路由)处理; + +- 即使后续修改 UserModel 的数据获取方式(比如从真实数据库查询),只要传递给视图的 user 数据结构不变,视图无需任何修改。 + +## 四、不同框架中视图的形式 + +框架 / 语言|视图的常见形式 +-|- +Flask/Django|HTML 模板(Jinja2/DTL) +Vue/React|组件(.vue/.jsx 文件) +Android|XML 布局文件 + 界面控件 +iOS|Storyboard/XIB + SwiftUI 视图 + +## 总结 + +- **核心作用**:视图是 MVC 的 “展示层”,只负责**展示数据**和**接收用户交互**,不处理业务逻辑; + +- **核心原则**:视图与模型解耦,仅依赖控制器传递的数据,逻辑全部交给控制器和模型处理; + +- **开发要点**:视图应保持 “轻量”,避免在视图中写业务逻辑,否则会破坏 MVC 的分层设计,增加维护成本。 \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20260108-\350\247\206\345\233\276.md" "b/\351\231\210\346\201\251\347\224\237/20260108-\350\247\206\345\233\276.md" new file mode 100644 index 0000000000000000000000000000000000000000..9e024c0768307aabb151cc67f716c7f6951b8ecf --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20260108-\350\247\206\345\233\276.md" @@ -0,0 +1,22 @@ +# 笔记本部 + +- mvc视图职责 +```bash + +- 数据展示:将模型数据渲染为HTML/UI +- 用户交互:提供表单、按钮等交互元素 +- 界面结构:定义页面布局和视觉呈现 +- 数据绑定:动态显示模型状态变化 + +``` + +- Razor视图 + +```c# +@model User +

欢迎,@Model.Name

+

上次登录:@Model.LastLogin

+ +``` + +## 练习 \ No newline at end of file diff --git "a/\351\231\210\346\201\251\347\224\237/20260109-MVC \344\270\255\347\232\204\345\270\270\347\224\250 Tag Helpers.md" "b/\351\231\210\346\201\251\347\224\237/20260109-MVC \344\270\255\347\232\204\345\270\270\347\224\250 Tag Helpers.md" new file mode 100644 index 0000000000000000000000000000000000000000..60a17f15be70554bc85faf1d1b5d092abb987ee7 --- /dev/null +++ "b/\351\231\210\346\201\251\347\224\237/20260109-MVC \344\270\255\347\232\204\345\270\270\347\224\250 Tag Helpers.md" @@ -0,0 +1,334 @@ +# MVC 中的常用 Tag Helpers 详解 + +**你想要了解 MVC 中常用的 Tag Helpers,我会从核心概念、优势、常用内置 Tag Helpers 及实战示例等方面,全面为你讲解(以 ASP.NET Core MVC 为例,这是 Tag Helpers 应用最广泛的场景)。** + +## 一、Tag Helpers 核心概述 + +- `核心定义`:Tag Helpers 是 `ASP.NET` Core MVC 提供的一组`服务器端组件`,它允许你直接在 Razor 视图(.cshtml)中以 HTML 标签 / 属性的形式编写服务器端逻辑,无需大量嵌入 @ 代码块,让视图代码更简洁、更具可读性。 +- 核心优势: + + - 语法贴近原生 HTML,前端开发者和后端开发者都易于理解。 + + - 减少 Razor 视图中的 @if、@for 等嵌入式代码,让视图更专注于展示逻辑。 + + - 提供强类型支持,编译时即可发现错误,比传统 HTML 辅助方法更健壮。 + + - 可自定义扩展,满足项目个性化需求。 +- 核心使用前提: + + - 项目中已引用 Microsoft.AspNetCore.Mvc.TagHelpers 包(ASP.NET Core MVC 模板默认包含)。 + + - 视图文件(或 _ViewImports.cshtml)中添加引用指令:@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers(全局引用所有内置 Tag Helpers)。 + +## 二、MVC 常用内置 Tag Helpers + +以下是开发中最常用的内置 Tag Helpers,按使用场景分类讲解,包含核心功能和实战示例。 + +### 1. 表单相关 Tag Helpers(最核心,用于构建强类型表单) + +表单相关 Tag Helpers 是 MVC 开发中使用频率最高的,核心用于绑定模型、生成表单元素及验证信息。 + +#### (1)form 标签助手 + +- 核心功能:自动生成表单的 action 和 method 属性,绑定控制器动作方法,无需手动拼接 URL。 + +- 关键属性: + + - asp-action:指定目标控制器的动作方法名。 + + - asp-controller:指定目标控制器名(若缺省,默认使用当前视图对应的控制器)。 + + - asp-method:指定 HTTP 请求方法(GET/POST/PUT/DELETE 等,默认 POST)。 + + - asp-antiforgery:是否启用防跨站请求伪造(CSRF)验证(默认 true,自动生成隐藏验证字段)。 + +- 示例: + +```html + +
+ +
+编译后生成的 HTML(自动拼接 URL、添加防伪造令牌): +html +预览 +
+ +
+``` + +#### (2)input 标签助手 + +- 核心功能:强类型绑定模型属性,自动生成 name、id、type 属性,且会自动填充模型数据(如编辑场景)。 + +- 关键属性:asp-for:指定要绑定的模型属性(强类型支持,编译时校验属性是否存在)。 + +- 自动特性:根据模型属性的类型和数据注解,自动匹配 input 类型(如 bool 对应 checkbox,DateTime 对应 date,[EmailAddress] 对应 email)。 + +- 示例(先定义模型): + +```csharp +// 用户注册模型 +public class RegisterModel +{ + public string UserName { get; set; } + + [EmailAddress] + public string Email { get; set; } + + [DataType(DataType.Password)] + public string Password { get; set; } + + public bool RememberMe { get; set; } +} +``` + +- 视图中的 input 标签助手使用: + +```html +@model RegisterModel + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+``` + +- 编译后生成的 HTML(自动匹配类型、填充属性): + +```html +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+``` + +#### (3)label 标签助手 + +- 核心功能:自动生成 for 属性(与对应 input 的 id 匹配),并自动填充标签文本(优先使用模型数据注解的 [Display] 特性,无则使用属性名)。 + +- 关键属性:asp-for:指定绑定的模型属性,与 input 对应。 + +- 优化示例(添加数据注解): + +```csharp +public class RegisterModel +{ + [Display(Name = "用户名")] + public string UserName { get; set; } + + [Display(Name = "邮箱地址")] + [EmailAddress] + public string Email { get; set; } +} +``` + +- 视图使用: + +```html + +``` + +- 编译后生成: + +```html + +``` + +#### (4)validation-summary & validation-message(验证提示相关) + +- 核心功能:展示模型验证的错误信息,配合 ASP.NET Core 的数据注解验证使用。 + +- validation-summary:展示所有验证错误(全局汇总),关键属性 +asp-validation-summary(取值:All/ModelOnly/None)。 + +- validation-message:展示单个属性的验证错误,关键属性 asp-validation-for,指定对应模型属性。 + +- 示例: + +```html + +
+ +
+ + + + +
+``` + +### 2. 链接相关 Tag Helpers + +#### (1)a 标签助手 + +- 核心功能:自动生成 URL 链接,绑定控制器和动作方法,无需手动拼接路由地址,支持路由参数。 + +- 关键属性: + + - asp-action:目标动作方法名。 + + - asp-controller:目标控制器名。 + + - asp-route-{param}:传递路由参数({param} 替换为实际参数名)。 + + - asp-area:指定区域(Area)(多区域项目使用)。 + +- 示例: + +```html + +首页 + + +查看用户详情 +``` + +- 编译后生成的 HTML(根据项目路由配置自动拼接 URL): + +```html +首页 +查看用户详情 +``` + +#### (2)link 标签助手 + +- 核心功能:主要用于引入 CSS 文件,支持缓存破坏(自动添加版本号或哈希值,避免浏览器缓存旧样式)。 + +- 关键属性:asp-href-include、asp-href-exclude、asp-append-version(是否添加版本号,默认 false)。 + +- 示例: + +```html + + +``` + +- 编译后生成的 HTML(自动添加 v 参数作为版本号): + +```html + +``` + +### 3. 其他常用 Tag Helpers + +#### (1)img 标签助手 + +- 核心功能:用于展示图片,支持缓存破坏(与 link 标签助手类似),自动生成 src 属性。 + +- 关键属性:asp-src、asp-append-version。 + +- 示例: + +```html +网站logo +``` + +#### (2)select & option 标签助手 + +- 核心功能:快速构建下拉选择框,支持强类型绑定模型属性,自动填充选项并选中对应值。 + +- 关键属性: + + - select 标签:asp-for(绑定模型属性)、asp-items(绑定下拉选项数据源)。 + + - 数据源通常为 IEnumerable 类型。 + +- 示例: + +```csharp +// 控制器中准备下拉选项数据源 +public IActionResult Register() +{ + // 性别选项 + var genderItems = new List + { + new SelectListItem { Text = "男", Value = "1" }, + new SelectListItem { Text = "女", Value = "2" }, + new SelectListItem { Text = "保密", Value = "0", Selected = true } + }; + + ViewBag.GenderItems = genderItems; + return View(); +} + +// 模型中添加性别属性 +public class RegisterModel +{ + [Display(Name = "性别")] + public string Gender { get; set; } +} +``` + +- 视图中使用: + +```html +
+ + +
+``` + +- 编译后生成的 HTML(自动选中默认项): + +```html +
+ + +
+``` + +## 三、Tag Helpers 核心优势总结 + +- 简化视图代码:以 HTML 原生语法为基础,减少 Razor 嵌入式代码,提高可读性和可维护性。 + +- 强类型支持:编译时校验模型属性,提前发现错误,比传统 HTML 辅助方法更可靠。 + +- 自动适配:根据模型属性和数据注解,自动生成对应的 HTML 属性和类型,减少手动编码工作量。 + +- 易于扩展:支持自定义 Tag Helpers,满足项目个性化需求(如自定义分页标签、按钮标签等)。 + +## 四、总结 + +- Tag Helpers 是 ASP.NET Core MVC 的核心视图辅助组件,以服务器端 HTML 标签形式工作,让视图更简洁。 + +- 常用内置 Tag Helpers 集中在表单、链接、验证三大场景,其中 form、input、a 是开发必备。 + +- 核心属性多以 asp- 为前缀,asp-for(强类型绑定)、asp-action/asp-controller(路由绑定)是高频使用属性。 + +- Tag Helpers 提供强类型支持和缓存优化,相比传统 Razor 辅助方法,更适合现代 MVC 项目开发。 +