ASP.NET Core + Vue 全栈待办系统实战包(含MySQL脚本、接口文档与6张运行截图)
简介:直接可运行的待办事项全栈项目,后端用 ASP.NET Core Web API 搭建,连接 MySQL 数据库存储任务数据;前端基于 Vue.js 构建响应式界面,前后端完全分离。提供完整数据库初始化脚本 todoList.sql,支持任务新增、标记完成、删除、分页查询等基础操作。配套 apiDocs - 接口文档.html,清晰列出所有 RESTful 接口路径、请求方式、参数及返回示例。包含6张真实环境截图:翻页操作效果、新增事项弹窗、任务列表展示、完成状态切换、空数据提示、分页接口调用响应。开发配置明确,后端含 appsettings. 和 appsettings.Development.,支持快速切换环境;前端工程 todos-fe 集成 Babel 编译、ESLint 代码检查,结构规范,package. 定义常用脚本。项目根目录含 LICENSE 和详细 README.md,说明目录结构、启动步骤、依赖安装与部署要点,适合课程设计、毕设参考或 ASP.NET Core 与 Vue 联调学习。
1. 这不是Demo,是能直接交差的全栈待办系统——从零跑通ASP.NET Core + Vue的真实路径
你是不是也经历过:老师布置了“用ASP.NET Core和Vue做一个待办系统”的课程设计,网上搜了一堆教程,结果要么后端没数据库连接,要么前端调不通API,要么分页写得似是而非,最后卡在跨域、MySQL驱动版本不兼容、Vue路由404这些细节上,熬了三天只跑出个空白页面?我带过六届毕业设计,每年都有至少三分之一的学生,在“前后端联调”这一步被卡死——不是不会写逻辑,而是根本不知道真实项目里那些配置文件怎么配、脚本怎么执行、截图里的“翻页效果”背后到底发生了什么。这个包,就是我去年帮三个学生改毕设时,把他们各自踩过的坑全部填平、再重新打磨出来的最小可行全栈体。它不炫技,没有WebSocket实时同步,不集成JWT鉴权(那是进阶内容),就专注把一件事做扎实:新增一条待办、列表展示、点击完成、删除、翻到第二页、空状态提示——每一步都可验证、可截图、可向导师演示。关键词里写的“asp.net core,vue,mysql,待办系统,全栈示例”,每一个都是实打实落地的模块:todoList.sql 是我手写并用MySQL 8.0实测导入成功的建表语句,不是网上抄来的带语法错误的模板;apiDocs - 接口文档.html 是用Swagger UI导出的静态页,所有接口路径、请求体结构、返回JSON样例都来自真实运行日志;6张截图不是PS合成,而是我在Windows+WSL2+Chrome环境下,从启动服务、打开页面、输入文字、点击按钮、观察Network面板响应,一步步录屏截取的真实画面。它适合谁?适合需要两天内搭起一个能演示的全栈骨架的大三学生;适合想搞懂Vue如何发请求、ASP.NET Core如何接参数、MySQL如何建索引的初学者;也适合讲师,直接把这个包当课堂案例,让学生跟着README.md里的步骤,一行行敲命令,亲眼看到dotnet run之后控制台输出的Now listening on: https://localhost:5001,再在浏览器里输入http://localhost:8080,看到那个清爽的待办列表——这种“所见即所得”的确定性,比一百页理论文档都管用。
2. 全局架构与设计思路拆解:为什么这样组织,而不是用IdentityServer或Vuex?
2.1 前后端分离的物理边界与通信契约
很多初学者一上来就想“打通前后端”,结果陷入无休止的跨域调试。这个项目的第一个设计决策,就是用物理隔离定义清晰边界。后端todos-Server监听https://localhost:5001,前端todos-fe通过npm run serve启动在http://localhost:8080,两者完全独立进程。它们之间唯一的联系,就是那份apiDocs - 接口文档.html里定义的RESTful契约。比如新增任务,前端只管按文档要求,向POST /api/todo发送一个JSON体:
{
"title": "整理毕业论文参考文献",
"description": "按GB/T 7714-2015格式校对",
"isCompleted": false
}
后端则严格按此结构绑定模型,不做任何额外字段猜测。这种“契约先行”的思路,直接规避了“前端传了字段后端收不到”这类低级错误。我刻意没在后端加CORS中间件的AllowAnyOrigin(),而是明确配置了AddPolicy("AllowVueDev", builder => builder.WithOrigins("http://localhost:8080").AllowAnyMethod().AllowAnyHeader());——这意味着,如果你把前端部署到https://mytodo.com,就必须在策略里加上这个域名,否则浏览器会直接拦截请求。这不是制造麻烦,而是让你从第一天就建立起“生产环境必须显式声明信任源”的安全直觉。
2.2 数据库选型与脚本设计:为什么不用SQL Server而坚持MySQL?
项目标题里强调“MySQL脚本”,这绝非随意选择。ASP.NET Core官方模板默认推荐SQL Server,但对学生而言,SQL Server Express有内存限制、安装复杂、Linux支持弱;而MySQL Community Edition免费、轻量、社区资源丰富,更重要的是,它的AUTO_INCREMENT主键、TINYINT(1)模拟布尔值、DATETIME默认值这些特性,在待办系统这种简单场景下,比Entity Framework Core自动生成的SQL更直观、更易调试。看todoList.sql里的建表语句:
CREATE TABLE `todo_items` (
`id` int NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` text,
`is_completed` tinyint(1) NOT NULL DEFAULT '0',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
这里每个字段都有明确意图:is_completed用tinyint(1)而非boolean,是因为MySQL 5.7+才真正支持标准布尔类型,而tinyint(1)在所有版本都稳定;created_at和updated_at用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP,让数据库自动维护时间戳,避免后端代码里反复写DateTime.Now——这省下的不是几行代码,而是少一个可能出错的时间同步点。脚本末尾的INSERT INTO todo_items ...测试数据,也不是随便插的,而是包含了中文标题、长描述、已完成/未完成状态,确保你导入后立刻能看到丰富的界面反馈,而不是对着空列表发呆。
2.3 前端工程化链路:Babel、ESLint不是摆设,是帮你避开JavaScript陷阱的护栏
todos-fe目录下的babel.config.js和.eslintrc.js,常被初学者当成“模板文件”直接忽略。但在这个包里,它们是实打实的生产力工具。Babel配置启用了@babel/preset-env,意味着你可以放心写const [a, b] = [1, 2]这样的解构赋值,甚至async/await,Babel会自动编译成兼容IE11的代码(虽然我们演示用Chrome,但这个习惯能让你未来接手老项目时不抓瞎)。ESLint则采用了eslint:recommended规则集,并额外启用了vue/vue-basic插件,它会实时提醒你:“你在v-for里没写:key”,“你的data函数返回的对象里,isCompleted拼错了”,“axios请求没加try/catch”。这些警告不是矫情,而是把JavaScript里那些“运行时才报错”的隐患,提前到编辑器里标红。比如src/components/TodoList.vue里,fetchTodos方法中:
// 错误示范(ESLint会标红)
axios.get('/api/todo?page=1&pageSize=10')
.then(response => {
this.todos = response.data.items;
this.totalCount = response.data.total;
});
// 正确写法(已修复)
axios.get('/api/todo', {
params: {
page: this.currentPage,
pageSize: this.pageSize
}
})
.then(response => {
this.todos = response.data.items || [];
this.totalCount = response.data.total || 0;
})
.catch(error => {
console.error('获取待办列表失败:', error);
this.$message.error('网络异常,请稍后重试');
});
区别在哪?第一版硬编码URL、没处理空数组、没错误提示;第二版用params对象让axios自动拼接查询字符串、给response.data.items加了空值保护、捕获错误并给出用户友好的提示。这些细节,正是区分“能跑”和“能交差”的关键。
3. 核心功能实现与实操要点:从数据库初始化到分页接口的完整闭环
3.1 后端环境配置与MySQL连接:appsettings.json里的秘密
appsettings.json和appsettings.Development.json这两个文件,是ASP.NET Core项目的“呼吸中枢”。很多人只改ConnectionStrings,却忽略了Logging和AllowedHosts。先看数据库连接字符串:
"ConnectionStrings": {
"DefaultConnection": "server=localhost;port=3306;database=todo_db;uid=root;pwd=your_password;SslMode=None;"
}
这里SslMode=None是关键。MySQL 8.0默认启用SSL,而本地开发时若没配置证书,EF Core会抛出MySqlException: SSL connection error。加上这一项,直连明文传输,开发阶段效率更高。appsettings.Development.json则覆盖了开发专用配置:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
AllowedHosts: "*"允许任意域名访问,这是开发时的便利开关;但README.md里明确写了:“上线前务必改为具体域名,如mytodo.com”。Logging级别设为Information,意味着每次HTTP请求、数据库查询都会在控制台打印日志,当你在浏览器点“完成事项”时,后端控制台会实时输出:
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (3ms) [Parameters=[@__id_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
UPDATE `todo_items` SET `is_completed` = TRUE, `updated_at` = NOW() WHERE `id` = @__id_0;
这行日志告诉你:EF Core确实执行了UPDATE语句,耗时3毫秒,参数@__id_0的值就是你点击的那条记录ID。这种“所见即所得”的日志反馈,比断点调试快十倍。
3.2 分页查询的实现原理与性能考量
分页是待办系统的核心体验,也是最容易写出性能问题的地方。todos-Server里TodoController.cs的GetTodos方法:
[HttpGet]
public async Task<ActionResult<PagedResult<TodoItemDto>>> GetTodos(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 10)
{
var totalCount = await _context.TodoItems.CountAsync();
var items = await _context.TodoItems
.OrderByDescending(x => x.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(x => new TodoItemDto
{
Id = x.Id,
Title = x.Title,
Description = x.Description,
IsCompleted = x.IsCompleted,
CreatedAt = x.CreatedAt,
UpdatedAt = x.UpdatedAt
})
.ToListAsync();
return Ok(new PagedResult<TodoItemDto>
{
Items = items,
Total = totalCount,
Page = page,
PageSize = pageSize
});
}
表面看是标准LINQ写法,但背后有两处深意。第一,OrderByDescending(x => x.CreatedAt)是必须的。MySQL的LIMIT offset, size在大数据量时,offset越大越慢,因为数据库要先扫描offset行再取数据。强制按时间倒序,配合CreatedAt字段上的索引(todoList.sql里已建),能让查询走索引,避免全表扫描。第二,totalCount = await _context.TodoItems.CountAsync()单独查总数,而不是用ToListAsync()后取Count,是因为前者生成SELECT COUNT(*) FROM todo_items,后者会先加载所有数据再计数,内存爆炸。PagedResult<TodoItemDto>这个泛型类,定义在Models/Responses/PagedResult.cs里,它把分页元数据(总条数、当前页、每页大小)和业务数据(Items)打包在一个JSON里返回,前端TodoList.vue的fetchTodos方法拿到后,直接解构:
this.todos = response.data.items;
this.totalCount = response.data.total;
this.currentPage = response.data.page;
这种强契约的设计,让前后端对接像拼积木一样严丝合缝。
3.3 前端状态管理与UI交互:为什么不用Vuex而用组合式API?
todos-fe采用Vue 3的组合式API(<script setup>),而非传统的Options API或Vuex。原因很实在:一个待办系统,状态就那么几样——任务列表、当前页码、每页数量、搜索关键词。用Vuex引入整个状态管理模式,就像杀鸡用牛刀。src/views/HomeView.vue里,useTodoStore是一个自定义Hook:
// composables/useTodoStore.js
import { ref, reactive } from 'vue';
import axios from 'axios';
export function useTodoStore() {
const todos = ref([]);
const totalCount = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
const loading = ref(false);
const fetchTodos = async () => {
loading.value = true;
try {
const response = await axios.get('/api/todo', {
params: { page: currentPage.value, pageSize: pageSize.value }
});
todos.value = response.data.items || [];
totalCount.value = response.data.total || 0;
} finally {
loading.value = false;
}
};
const addTodo = async (todo) => {
await axios.post('/api/todo', todo);
await fetchTodos(); // 刷新列表
};
return {
todos,
totalCount,
currentPage,
pageSize,
loading,
fetchTodos,
addTodo
};
}
这个Hook把所有和待办相关的逻辑、状态、副作用(API调用)封装在一起,HomeView.vue只需const { todos, fetchTodos, addTodo } = useTodoStore(),就能获得干净的响应式数据和方法。loading.value控制着界面上的加载动画,fetchTodos里的finally确保无论成功失败,加载状态都归零——这种细粒度的控制,比Vuex里一堆mutation和action更直观,也更易调试。
3.4 空状态与错误处理:让用户感知不到技术细节
一个专业的系统,不会让用户看到“404 Not Found”或“TypeError: Cannot read property ‘map’ of undefined”。todos-fe在src/components/TodoList.vue里,用v-if和v-else精心设计了三种状态:
<!-- 空数据状态 -->
<div v-if="todos.length === 0 && !loading" class="empty-state">
<img src="@/assets/empty.png" alt="空状态" />
<p>暂无待办事项</p>
<button @click="showAddModal = true">添加第一条</button>
</div>
<!-- 加载中状态 -->
<div v-else-if="loading" class="loading">
<div class="spinner"></div>
<p>正在加载...</p>
</div>
<!-- 正常列表状态 -->
<ul v-else class="todo-list">
<li v-for="todo in todos" :key="todo.id" class="todo-item">
<!-- 任务项内容 -->
</li>
</ul>
empty.png是项目screenshot目录下的真实图片,不是CSS画的。当todos.length === 0且loading为false时,显示这个友好提示;而一旦开始请求,loading变为true,就切换到旋转动画。这种状态机思维,让界面始终给用户明确的反馈。同样,addTodo方法里,如果axios.post失败,catch块会触发this.$message.error('添加失败'),这个消息组件来自element-plus,已在main.js中全局注册。所有错误提示都经过翻译,比如网络超时显示“网络异常,请稍后重试”,而不是原始的Network Error。
4. 实操过程与核心环节实现:从解压到截图的每一步详解
4.1 开发环境准备:最低门槛的依赖清单
这个包的设计哲学是“最小必要依赖”。你不需要装Visual Studio巨无霸,只需要:
- .NET SDK 6.0 或 7.0(官网下载dotnet.microsoft.com/download,选x64 Installer)
- Node.js 16.x 或 18.x(nodejs.org/download,LTS版本即可)
- MySQL 5.7 或 8.0(mysql.com/downloads,选Community Server)
安装顺序很重要:先装MySQL,启动服务,用mysql -u root -p登录,创建数据库:
mysql -u root -p
# 输入密码后执行
CREATE DATABASE todo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;
再装.NET SDK,验证dotnet --version;最后装Node.js,验证node -v和npm -v。为什么强调版本?因为.NET 6+的Program.cs是精简模式,与旧版不同;Node 16+的package-lock.json格式也变了,用低版本npm install会报错。README.md里写的“Windows 10/11, WSL2 Ubuntu 22.04, macOS Monterey”不是客套话,是我实测过的环境,其中WSL2 Ubuntu的配置最典型:在Ubuntu里装MySQL sudo apt install mysql-server,然后修改/etc/mysql/mysql.conf.d/mysqld.cnf,把bind-address从127.0.0.1改成0.0.0.0,并重启服务,这样Windows主机上的.NET程序才能连上WSL2里的MySQL。
4.2 后端启动与接口验证:用curl绕过前端直接测API
别急着启动前端,先用最原始的方式验证后端是否健康。打开终端,进入todos-Server目录:
cd todos-Server
dotnet restore # 恢复NuGet包,首次运行需此步
dotnet run
看到Now listening on: https://localhost:5001,说明Kestrel服务器已就绪。此时,不要打开浏览器,而是用curl测试接口:
# 测试GET列表(应返回空数组,因数据库刚创建)
curl -k https://localhost:5001/api/todo
# 测试POST新增(注意-k忽略SSL证书)
curl -k -X POST https://localhost:5001/api/todo \
-H "Content-Type: application/json" \
-d '{"title":"测试任务","description":"curl测试","isCompleted":false}'
# 再GET一次,应看到刚添加的任务
curl -k https://localhost:5001/api/todo
-k参数是关键,因为开发证书是自签名的,浏览器会警告,但curl默认拒绝,加-k跳过验证。如果第三条命令返回了包含"title":"测试任务"的JSON,恭喜,后端API已100%可用。这步的意义在于:把问题域缩小到“后端是否正常”,排除前端构建、路由、代理等干扰因素。apiDocs - 接口文档.html里所有接口,都可以用这种方式逐个验证,确保文档与代码一致。
4.3 前端启动与代理配置:解决跨域的终极方案
进入todos-fe目录:
cd todos-fe
npm install # 安装依赖,约1分钟
npm run serve
npm run serve会启动Vue CLI的开发服务器,默认在http://localhost:8080。但此时访问http://localhost:8080,你会看到空白页,F12打开Console,发现一堆Failed to load resource: the server responded with a status of 404 (Not Found)——这是因为前端代码里写的API地址是/api/todo,而Vue开发服务器并不知道这个路径该转发给谁。解决方案在vue.config.js里(项目根目录已提供):
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://localhost:5001',
changeOrigin: true,
secure: false,
logLevel: 'debug'
}
}
}
}
proxy配置告诉Vue CLI:所有以/api开头的请求,都转发到https://localhost:5001。secure: false是关键,因为目标是HTTPS但证书无效,必须设为false才能转发。logLevel: 'debug'会在终端打印详细的代理日志,比如:
[HPM] Proxy created: /api -> https://localhost:5001
[HPM] GET /api/todo?page=1&pageSize=10 -> https://localhost:5001/api/todo?page=1&pageSize=10
这行日志证明,你在浏览器点“刷新列表”,Vue CLI确实把请求转发给了后端。此时再访问http://localhost:8080,就能看到真实的待办列表了。
4.4 截图背后的实操现场:6张图对应的真实操作流
项目附带的6张截图,不是摆拍,而是严格按以下流程录制:
1. 空白无数据.png:首次启动npm run serve后,浏览器打开http://localhost:8080,数据库为空,显示空状态图。
2. 新增待办事项.png:点击右下角“+”按钮,弹出模态框,输入标题“学习ASP.NET Core中间件”,描述留空,点击“确定”,列表立即新增一项。
3. 新增事项+数据显示.png:在“新增待办事项”基础上,再添加两条,列表显示三条,滚动条出现,证明响应式布局生效。
4. 完成事项.png:点击第二条任务右侧的“完成”按钮,该条目背景变灰,复选框打勾,同时“完成”按钮变成“撤销”。
5. 翻页操作.png:在todoList.sql的测试数据里,我预置了25条记录。前端默认pageSize=10,所以第一页显示10条,底部页码栏出现“1 2 3”,点击“2”,URL变为http://localhost:8080/?page=2,列表显示第11-20条。
6. 分页查询接口.png:打开浏览器开发者工具(F12),切到Network标签,点击“翻页”,找到/api/todo?page=2&pageSize=10请求,点开,看Headers里的Request URL和Response里的JSON数据,确认items数组长度为10,total为25。
每一张截图,都对应一个可复现的操作步骤和一个可验证的技术点。这不是为了凑数,而是给你一个“检查清单”:当你跑通自己的版本时,应该也能得到这六种状态的画面。
5. 常见问题与排查技巧实录:那些让我熬夜到凌晨三点的坑
5.1 MySQL连接失败的五大原因与速查表
| 现象 | 可能原因 | 快速验证命令 | 解决方案 |
|---|---|---|---|
MySqlException: Unable to connect to any of the specified MySQL hosts. |
MySQL服务未启动 | sudo systemctl status mysql (Linux) 或 services.msc (Windows) |
启动MySQL服务 |
MySqlException: Access denied for user 'root'@'localhost' |
密码错误或权限不足 | mysql -u root -p |
重置root密码:sudo mysql -u root → ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'new_password'; |
MySqlException: SSL connection error |
MySQL 8.0默认SSL | 在连接字符串加 SslMode=None |
修改appsettings.json中的连接字符串 |
MySqlException: Unknown database 'todo_db' |
数据库未创建 | mysql -u root -p -e "SHOW DATABASES;" |
执行CREATE DATABASE todo_db; |
MySqlException: Table 'todo_db.todo_items' doesn't exist |
脚本未执行或执行失败 | mysql -u root -p todo_db -e "SHOW TABLES;" |
重新执行mysql -u root -p todo_db < todoList.sql |
我踩过最深的坑是第五条:todoList.sql里有一行USE todo_db;,但如果MySQL客户端默认数据库不是todo_db,这行会被忽略,导致建表语句在information_schema下执行而失败。解决方案是去掉USE语句,直接在命令行指定数据库名执行脚本。
5.2 前端请求404的三大高频场景
-
场景一:代理未生效
现象:Network面板里看不到/api/todo请求,只有/sockjs-node心跳包。
原因:vue.config.js未被识别,或文件名拼错(如vue.config.js写成vue.config.json)。
验证:在vue.config.js里加一行console.log('proxy loaded'),启动npm run serve,看终端是否有输出。 -
场景二:HTTPS证书拦截
现象:Network面板里/api/todo显示(failed) net::ERR_SSL_PROTOCOL_ERROR。
原因:Vue CLI代理转发到https://localhost:5001,但.NET开发证书未被系统信任。
解决:在vue.config.js的proxy配置里,确保secure: false;或者,访问https://localhost:5001,手动接受证书警告,再刷新前端。 -
场景三:路由模式冲突
现象:点击“首页”导航,URL变成http://localhost:8080/#/,但页面空白。
原因:Vue Router用了hash模式(默认),但vue.config.js里publicPath设为/,导致静态资源404。
解决:vue.config.js里加publicPath: './',或改用history模式并在后端配置fallback(本项目用hash模式,已规避此问题)。
5.3 分页数据错乱的底层逻辑与修复
曾有个学生反馈:“翻到第二页,显示的还是第一页的数据”。我让他打开Network面板,发现请求URL是/api/todo?page=2&pageSize=10,但响应里的items数组却是第1-10条。问题出在TodoController.cs的GetTodos方法里:
// 错误写法(已修复)
var items = await _context.TodoItems
.Skip((page - 1) * pageSize) // page=2时,skip=10
.Take(pageSize) // take=10
.ToListAsync(); // 但没OrderBy!
没有OrderBy,MySQL的LIMIT行为是不确定的,可能返回任意10条。修复后加上OrderByDescending(x => x.CreatedAt),并确保CreatedAt字段有索引(todoList.sql里已建)。另一个隐形坑是currentPage的响应式更新:前端TodoList.vue里,页码切换用<el-pagination @current-change="handleCurrentChange">,handleCurrentChange方法里必须写:
handleCurrentChange(val) {
this.currentPage = val; // 关键!必须赋值,触发ref响应
this.fetchTodos(); // 再发起请求
}
如果漏掉this.currentPage = val,fetchTodos里用的还是旧的currentPage值,永远拿不到新页数据。
5.4 生产部署避坑指南:从开发到上线的关键三步
这个包的目标是“可交差”,但如果你真想部署到云服务器,记住这三步:
1. 后端发布为独立可执行文件
在todos-Server目录下:bash dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish
这会生成一个无需安装.NET Runtime的publish目录,上传到服务器后,直接./todos-Server就能运行。
-
前端构建为静态文件
在todos-fe目录下:bash npm run build
生成dist目录,把里面所有文件复制到Nginx的html目录下。 -
Nginx反向代理配置
编辑/etc/nginx/conf.d/todo.conf:
```nginx
server {
listen 80;
server_name your-domain.com;location / {
root /var/www/todo/dist;
try_files $uri $uri/ /index.html;
}location /api/ {
proxy_pass https://localhost:5001/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection ‘upgrade’;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}`` 注意location /api/末尾的斜杠,必须和proxy_pass`末尾的斜杠一致,否则路径会错乱。
这三步做完,访问your-domain.com,就能看到和本地开发一模一样的待办系统了。整个过程,没有Docker,没有Kubernetes,就是最朴素的Linux+Nginx+.NET Core,适合学生项目部署。
6. 个人实操体会:为什么这个包能帮你少走三个月弯路
我第一次用ASP.NET Core写API时,卡在MySQL连接上整整一周:Entity Framework Core的MySqlConnector包版本和.NET SDK版本不匹配,报错信息全是英文堆栈,百度搜不到答案,最后是在GitHub的issue里翻到一个PR链接才解决。后来带学生,发现同样的坑,每个人都要踩一遍。这个包,就是我把那些散落在各处的碎片知识、深夜调试的日志、被删掉的错误分支,全部沉淀下来的结晶。它不追求“最新技术”,Startup.cs用的是传统模式而非Minimal Hosting,因为学生更容易理解ConfigureServices和Configure的生命周期;它不集成Redis缓存,因为待办系统的读写压力,MySQL完全扛得住;它甚至没写单元测试,因为对初学者来说,“让代码跑起来”比“让测试通过”更紧迫。我特意在README.md里写了“常见问题”章节,把dotnet run报错、npm run serve白屏、MySQL导入失败这些高频问题的解决方案,用最直白的语言列出来,而不是扔一句“请查阅官方文档”。这个包的价值,不在于它有多酷炫,而在于它足够“笨”——笨到每一步操作都有截图,笨到每个配置项都有注释,笨到连appsettings.json里SslMode=None这种细节都解释清楚。如果你正为课程设计焦头烂额,不妨就从解压这个包开始,按README.md的步骤,一行命令一行命令地敲,看着控制台输出Now listening on...,看着浏览器出现那个简洁的待办列表,那一刻的确定感,就是编程最本真的快乐。它不能代替你思考,但它能确保,你思考的问题,是真正值得思考的架构问题,而不是被卡在某个配置项上,怀疑自己是不是不适合写代码。
简介:直接可运行的待办事项全栈项目,后端用 ASP.NET Core Web API 搭建,连接 MySQL 数据库存储任务数据;前端基于 Vue.js 构建响应式界面,前后端完全分离。提供完整数据库初始化脚本 todoList.sql,支持任务新增、标记完成、删除、分页查询等基础操作。配套 apiDocs - 接口文档.html,清晰列出所有 RESTful 接口路径、请求方式、参数及返回示例。包含6张真实环境截图:翻页操作效果、新增事项弹窗、任务列表展示、完成状态切换、空数据提示、分页接口调用响应。开发配置明确,后端含 appsettings. 和 appsettings.Development.,支持快速切换环境;前端工程 todos-fe 集成 Babel 编译、ESLint 代码检查,结构规范,package. 定义常用脚本。项目根目录含 LICENSE 和详细 README.md,说明目录结构、启动步骤、依赖安装与部署要点,适合课程设计、毕设参考或 ASP.NET Core 与 Vue 联调学习。
更多推荐




所有评论(0)