C#
综合实战与进阶路线
整合领域、SQLite、HTTP、配置、异步、测试与发布,完成可维护的 StudyTasks 项目闭环。
发布于 2026年7月23日
综合实战与进阶路线
本篇把前面的语言和工程能力合并为可安装的 StudyTasks 命令行应用。重点不是继续堆功能,而是让领域、数据库、网络、配置、取消、测试和交付形成闭环;任何步骤失败时,系统仍处于可解释、可恢复的状态。
一、学习目标
- 按依赖方向组装 Core、Infrastructure、Cli 和 Tests
- 让
add/list/done/delete/sync共享一套领域规则 - 用事务、取消和错误分类保护外部边界
- 在干净 .NET 10 环境完成测试、打包、安装和冒烟
最终命令:
study-tasks add "阅读 C# 文档"
study-tasks list
study-tasks done 1
study-tasks delete 1
study-tasks sync
二、最终结构与依赖
StudyTasks/
global.json
StudyTasks.slnx
Directory.Build.props
src/
StudyTasks.Core/
Models/StudyTask.cs
Ports/ITaskRepository.cs
Ports/IRemoteTaskClient.cs
Services/TaskService.cs
StudyTasks.Infrastructure/
Sqlite/SqliteTaskRepository.cs
Http/RemoteTaskClient.cs
StudyTasks.Cli/
Program.cs
CommandFactory.cs
appsettings.json
tests/
StudyTasks.Tests/
依赖只能由外向内:
Cli -> Core
Cli -> Infrastructure -> Core
Tests -> public interfaces
Core 不引用 System.CommandLine、Microsoft.Data.Sqlite、配置、日志或 HTTP 实现。Cli 是组合根,Infrastructure 只实现 Core 定义的端口。
统一编译基线:
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>14.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
稳定依赖固定为 System.CommandLine 2.0.10、Microsoft.Extensions 10.0.10、Microsoft.Data.Sqlite 10.0.10 和 xUnit v3 3.2.2。
三、领域模型与端口
领域对象只允许合法状态,外部能力由端口表达:
public sealed record StudyTask(
int Id,
string Title,
bool IsCompleted,
DateTimeOffset CreatedAt,
DateTimeOffset? CompletedAt)
{
public static StudyTask Create(string title, DateTimeOffset now)
{
string clean = title.Trim();
if (clean.Length is < 1 or > 120)
throw new ArgumentException("标题长度必须为 1~120");
return new(0, clean, false, now, null);
}
public StudyTask Complete(DateTimeOffset now) =>
IsCompleted ? this : this with
{
IsCompleted = true,
CompletedAt = now
};
}
public interface ITaskRepository
{
StudyTask Add(StudyTask task);
IReadOnlyList<StudyTask> List();
void Update(StudyTask task);
bool Delete(int id);
}
远端同步另由 IRemoteTaskClient 暴露可取消的异步方法。CLI、JSON、HTTP 和数据库行都先验证,再进入领域;CLI 不拼 SQL,仓储不打印消息,HTTP 客户端不决定退出码。
四、数据与同步边界
SQLite 同时用领域校验和数据库约束保护数据:
CREATE TABLE task (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL
CHECK (length(trim(title)) BETWEEN 1 AND 120),
status TEXT NOT NULL
CHECK (status IN ('todo', 'done')),
created_at TEXT NOT NULL,
completed_at TEXT NULL,
CHECK (
(status = 'todo' AND completed_at IS NULL)
OR
(status = 'done' AND completed_at IS NOT NULL)
)
);
所有用户值参数化;状态更新和本地审计处于同一短事务。网络读取不能放进数据库事务。
sync 的默认策略是全部成功或全部失败:
读取并验证配置
-> 发起带超时和取消的 HTTPS 请求
-> 限制响应大小并反序列化 DTO
-> 将全部 DTO 映射为合法领域对象
-> 检查 ID 唯一和跨记录不变量
-> 开启 SQLite 事务并替换数据
-> 提交后输出数量
任何网络、协议或数据错误都不修改本地数据库。若改为增量同步,必须另外定义游标、幂等键、冲突规则和删除语义,不能只比较本地时间。
五、配置、CLI 与错误契约
appsettings.json 提供非秘密默认值:
{
"StudyTasks": {
"Database": "tasks.db",
"ApiUrl": "https://api.example.com/tasks",
"TimeoutSeconds": 15,
"MaxConcurrency": 4
}
}
Token 通过 StudyTasks__ApiToken 提供。命令行、环境变量、环境专用 JSON、基础 JSON 依次覆盖。仅在执行 sync 时要求 Token;--help、--version 和本地 CRUD 不连接网络。
退出码保持稳定:
| 退出码 | 含义 |
|---|---|
| 0 | 成功 |
| 2 | 参数或配置错误 |
| 3 | 任务不存在 |
| 4 | 暂时性外部故障 |
| 5 | 数据或协议不兼容 |
| 130 | 用户取消 |
stdout 只放稳定结果,stderr 放用户可操作的错误,结构化日志记录诊断字段。秘密不得进入三者中的任何一个。
六、测试矩阵
| 场景 | 预期 |
|---|---|
| 空白或超长标题 | 拒绝且不写数据库 |
| 重复完成 | 幂等,不改变首次完成时间 |
| 未知 ID | stderr 提示,退出码 3 |
| 数据库约束失败 | 当前事务整体回滚 |
| 环境变量存在 | 覆盖 JSON 配置 |
| HTTP 401/429/500 | 正确分类,只有限重试幂等请求 |
| 非法或超大 JSON | 拒绝且本地数据不变 |
| 用户取消 | 传播取消,退出码 130 |
| 并发同步 | 同时请求数不超过配置 |
| NuGet Tool 安装 | 在源码目录外可运行帮助和 CRUD |
领域测试不接 I/O;SQLite 使用临时数据库;HTTP 使用自定义 HttpMessageHandler 或本地测试服务。测试必须可重复,不依赖公网、真实时间和执行顺序。
七、安全、性能与发布检查
- SQL 全部参数化,动态结构来自白名单
- API 只接受 HTTPS,Token 不写入文件或日志
- HTTP 有超时、外部取消、响应大小和内容类型检查
- 文件路径不能突破允许的数据目录
- 远端数据完整验证后才进入一个短事务
- 重试只用于暂时性且幂等的操作
- 并发有上限,创建的任务都被等待
- 迁移前备份,并实际演练恢复
性能先测量冷启动、查询计划、事务时长、HTTP 延迟、峰值内存和日志量,再决定是否使用索引、缓存或 ValueTask。不要用无限并发掩盖慢服务。
发布检查:
dotnet --info
dotnet restore --locked-mode
dotnet format --verify-no-changes
dotnet build StudyTasks.slnx -c Release \
--no-restore --warnaserror
dotnet test StudyTasks.slnx -c Release --no-build
dotnet pack src/StudyTasks.Cli -c Release --no-build
dotnet publish src/StudyTasks.Cli -c Release
随后在干净 .NET 10 环境安装工具,实际执行 add/list/done/delete/sync。发布记录应包含版本、源提交、SDK 与包版本、产物 SHA-256、已知限制和回滚步骤。
八、常见错误
- 让 CLI、仓储和 HTTP 客户端各自重复业务规则
- 在数据库事务中等待网络,扩大锁范围和失败影响
- 只验证成功路径,没有覆盖取消、超时和无效数据
- 记录完整配置对象,意外泄露 Token
- 在源码目录中通过烟测,却没有测试安装后的产物
九、练习与自测
- 为什么 Core 定义端口,而 Infrastructure 实现适配器?
- 为什么远端数据要先全部验证,再开启 SQLite 事务?
- 用户取消、超时、HTTP 失败和协议错误怎样分类?
- 如何证明并发没有超过资源上限?
- 如何证明 NuGet Tool 在干净环境中可安装运行?
- 二进制回滚与数据回滚为什么是两件事?
如果这些问题都能通过代码、测试和发布记录回答,你已经完成了从“会写 C# 语法”到“能交付 .NET 项目”的闭环。
十、官方资料
上一篇:NuGet、发布与部署 | 返回:C# 完整学习路线