我们将创建一个经典的“待办事项列表”(To-Do List)应用,这是一个非常适合展示 ASP.NET 核心功能的例子。
第一步:准备工作
在开始之前,请确保你已经安装了以下软件:
- .NET 6 SDK 或更高版本:这是运行和构建 ASP.NET 应用程序的基础。
- Visual Studio 2025:这是开发 ASP.NET 应用最流行的集成开发环境。
- 社区版是免费的,足以满足开发需求。
- 下载地址:https://visualstudio.microsoft.com/vs/community/
- 安装时,请确保勾选 “.NET 桌面开发” 或 “ASP.NET 和 Web 开发” 工作负载。
第二步:创建 ASP.NET Web 应用项目
- 打开 Visual Studio 2025。
- 点击“开始” -> “创建新项目”。
- 在模板搜索框中输入
ASP.NET Core,然后选择 “ASP.NET Core Web 应用” 模板,确保选择的是 C# 版本。 - 点击“下一步”。
- 为你的项目命名,
TodoWebApp,并选择一个位置来保存项目。 - 点击“下一步”。
- 在“其他信息”页面:
- 框架:选择最新的 .NET 版本(如 .NET 8.0)。
- 配置:选择 “Web 应用”,这会为我们创建一个使用 Razor Pages 的最小化项目,非常适合入门。
- 其他信息:保持默认即可。
- 点击“创建”。
Visual Studio 会为你生成一个基本的项目结构,并包含一些示例页面。
第三步:理解项目结构
让我们快速了解一下 Visual Studio 为我们创建的关键文件和文件夹:
Pages/:这个文件夹包含了所有基于 Razor 的页面,每个.cshtml文件都是一个网页,而对应的.cshtml.cs文件是该页面的 C# 代码后端(称为“代码隐藏模型”)。Index.cshtml和Index.cshtml.cs:网站的首页。Privacy.cshtml和Privacy.cshtml.cs:一个隐私页面。Error.cshtml和Error.cshtml.cs:用于处理错误。
wwwroot/:存放所有静态文件的地方,如 CSS 样式表、JavaScript 文件、图片等。appsettings.json:应用程序的配置文件,用于存储数据库连接字符串、API 密钥等。Program.cs:应用程序的入口点,在这里配置服务(如数据库、中间件)和请求管道。Startup.cs(在较新版本中,代码可能直接在Program.cs中):配置服务和应用的中间件。
第四步:创建“待办事项”功能
我们来动手实现核心功能。
定义数据模型
我们需要一个“待办事项”的类来表示数据。
- 在
TodoWebApp项目上右键 -> “添加” -> “新建文件夹”,命名为Models。 - 在
Models文件夹上右键 -> “添加” -> “类”,命名为TodoItem.cs。 - 打开
TodoItem.cs,并编写以下代码:
// Models/TodoItem.cs
namespace TodoWebApp.Models
{
public class TodoItem
{
public int Id { get; set; }
public string? Task { get; set; } // 使用 ? 表示可以为空
public bool IsDone { get; set; }
}
}
创建服务来管理数据
为了简单起见,我们不使用数据库,而是使用一个静态列表来存储待办事项,在实际应用中,你会使用数据库。
- 在
TodoWebApp项目上右键 -> “添加” -> “新建文件夹”,命名为Services。 - 在
Services文件夹上右键 -> “添加” -> “类”,命名为TodoService.cs。 - 编写代码来管理待办事项列表:
// Services/TodoService.cs
using TodoWebApp.Models;
namespace TodoWebApp.Services
{
public class TodoService
{
private readonly List<TodoItem> _todos = new();
private int _nextId = 1;
public List<TodoItem> GetAllTodos()
{
return _todos;
}
public TodoItem? GetTodoById(int id)
{
return _todos.FirstOrDefault(t => t.Id == id);
}
public void AddTodo(string task)
{
if (!string.IsNullOrWhiteSpace(task))
{
_todos.Add(new TodoItem { Id = _nextId++, Task = task, IsDone = false });
}
}
public void UpdateTodo(TodoItem todo)
{
var existingTodo = GetTodoById(todo.Id);
if (existingTodo != null)
{
existingTodo.Task = todo.Task;
existingTodo.IsDone = todo.IsDone;
}
}
public void DeleteTodo(int id)
{
var todo = GetTodoById(id);
if (todo != null)
{
_todos.Remove(todo);
}
}
}
}
注册服务
我们需要告诉应用程序 TodoService 是一个可用的服务。
打开 Program.cs 文件,在 builder.Services.AddRazorPages(); 这一行下面添加:
// Program.cs
using TodoWebApp.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
// 注册我们的 TodoService 为单例服务
builder.Services.AddSingleton<TodoService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
创建网页来显示和操作待办事项
我们将修改首页来展示我们的待办事项列表。
打开 Pages/Index.cshtml 文件,将其内容替换为:
@* Pages/Index.cshtml *@
@page
@model TodoWebApp.Pages.IndexModel
@{
ViewData["Title"] = "待办事项列表";
}
<div class="text-center">
<h1 class="display-4">我的待办事项</h1>
</div>
<div class="container mt-4">
<div class="row">
<div class="col-md-8 offset-md-2">
<!-- 添加新待办事项的表单 -->
<form method="post" class="mb-4">
<div class="input-group">
<input type="text" class="form-control" asp-for="NewTask" placeholder="输入新的待办事项..." />
<button type="submit" class="btn btn-primary">添加</button>
</div>
<span asp-validation-for="NewTask" class="text-danger"></span>
</form>
<!-- 待办事项列表 -->
@if (!Model.Todos.Any())
{
<div class="alert alert-info">
暂无待办事项,快来添加一个吧!
</div>
}
else
{
<ul class="list-group">
@foreach (var todo in Model.Todos)
{
<li class="list-group-item d-flex justify-content-between align-items-center @(todo.IsDone ? "list-group-item-success" : "")">
<div>
<input type="checkbox" class="form-check-input me-2" asp-for="@todo.IsDone"
onchange="submitForm('@Url.Page("Index", "Update", new { id = todo.Id })', { 'IsDone': this.checked })">
<span class="@todo.IsDone ? "text-decoration-line-through" : "")">@todo.Task</span>
</div>
<a href="@Url.Page("Index", "Delete", new { id = todo.Id })"
class="btn btn-sm btn-outline-danger"
onclick="return confirm('确定要删除这个待办事项吗?')">删除</a>
</li>
}
</ul>
}
</div>
</div>
</div>
@section Scripts {
<script>
function submitForm(url, data) {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
window.location.reload(); // 简单刷新页面以显示更改
})
.catch(error => console.error('Error:', error));
}
</script>
}
打开 Pages/Index.cshtml.cs 文件,替换其内容为:
// Pages/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using TodoWebApp.Models;
using TodoWebApp.Services;
namespace TodoWebApp.Pages
{
public class IndexModel : PageModel
{
private readonly TodoService _todoService;
// 通过构造函数注入服务
public IndexModel(TodoService todoService)
{
_todoService = todoService;
}
public List<TodoItem> Todos { get; set; } = new();
[BindProperty(SupportsGet = true)]
public string? NewTask { get; set; }
public void OnGet()
{
// 页面加载时,获取所有待办事项
Todos = _todoService.GetAllTodos();
}
public IActionResult OnPost()
{
if (!string.IsNullOrWhiteSpace(NewTask))
{
_todoService.AddTodo(NewTask);
}
return RedirectToPage(); // 重定向到当前页面,以清空输入框并刷新列表
}
public IActionResult OnPostUpdate(int id, bool isDone)
{
var todo = _todoService.GetTodoById(id);
if (todo != null)
{
todo.IsDone = isDone;
_todoService.UpdateTodo(todo);
}
return new OkResult(); // 返回成功状态
}
public IActionResult OnPostDelete(int id)
{
_todoService.DeleteTodo(id);
return RedirectToPage(); // 重定向到当前页面,刷新列表
}
}
}
添加一些样式
为了让页面看起来更美观,我们可以添加一些 CSS。
打开 wwwroot/css/site.css 文件,在文件末尾添加以下样式:
/* wwwroot/css/site.css */
/* 为待办事项列表添加一些基本样式 */
.list-group-item {
transition: background-color 0.2s;
}
.list-group-item-success {
background-color: #d4edda;
color: #155724;
}
.text-decoration-line-through {
text-decoration: line-through;
color: #6c757d;
}
.form-check-input:checked {
background-color: #28a745;
border-color: #28a745;
}
第五步:运行和测试
- 在 Visual Studio 中,确保选择了正确的启动项目(
TodoWebApp)。 - 点击工具栏上的绿色“播放”按钮(或按
F5)。 - Visual Studio 会编译并启动应用程序,默认会在浏览器中打开
https://localhost:xxxx(xxxx 是一个随机端口号)。
测试功能:
- 添加:在输入框中输入任务,点击“添加”按钮,列表应该会更新。
- 标记完成:勾选任务前面的复选框,任务文本应该会被划掉,并且背景色会改变。
- 删除:点击任务旁边的“删除”按钮,应该会弹出一个确认框,确认后任务会被移除。
第六步:发布和部署(可选)
当你准备将网站部署到服务器上时,可以执行以下步骤:
- 在 Visual Studio 中,右键点击项目解决方案资源管理器中的项目名称,选择“发布”。
- 选择“发布目标”,
- Azure:直接发布到 Microsoft Azure App Service。
- 文件夹:发布到本地的一个文件夹,你可以将这个文件夹中的所有文件通过 FTP/SFTP 上传到你的 Web 主机。
- Docker:打包成 Docker 容器。
- 按照向导完成发布配置,系统会为你构建一个用于生产环境的优化版本。
恭喜!你已经成功创建并运行了一个功能完整的 ASP.NET Web 应用。
这个教程涵盖了 ASP.NET 核心开发的核心概念:
- Razor Pages:用于构建页面的简单、直观的模型。
- 模型:定义数据结构。
- 服务:封装业务逻辑。
- 依赖注入:将服务注入到页面中。
- 表单处理:使用
asp-for和[BindProperty]来处理用户输入。 - 路由:
@page指令和OnGet/OnPost方法。
你可以基于这个项目继续扩展,
- 使用 Entity Framework Core 和 SQL Server 替换内存中的列表。
- 添加用户认证(登录/注册)。
- 使用 Bootstrap 或 Tailwind CSS 美化界面。
