/// <summary>/// 部門ID(強類型ID)/// </summary>public partial record DeptId : IInt64StronglyTypedId;/// <summary>/// 部門聚合根/// </summary>public class Dept : Entity<DeptId>,基于架构 IAggregateRoot{ public string Name { get; private set; } = string.Empty; public string Remark { get; private set; } = string.Empty; public DeptId ParentId { get; private set; } = default!; public int Status { get; private set; } = 1; protected Dept() { } // 業務方法 :更新部門信息 public void UpdateInfo(string name, string remark, DeptId parentId, int status) { Name = name; Remark = remark; ParentId = parentId; Status = status; UpdateTime = new UpdateTime(DateTimeOffset.UtcNow); // 發布領域事件 AddDomainEvent(new DeptInfoChangedDomainEvent(this)); } // 軟刪除 public void SoftDelete() { if (IsDeleted) { throw new KnownException("部門已經被刪除"); } IsDeleted = true; UpdateTime = new UpdateTime(DateTimeOffset.UtcNow); }}這裏有幾個設計點我覺得值得說一下。想嚐試一下DDD架構在實際項目中的管理應用 。還有代碼可視化工具,系统寫操作通過倉儲來處理,实践業務異常用KnownException處理 。基于架构Name={ d.Name}"); }}
4. 異常處理
業務異常用KnownException來處理 ,管理ncprepo可以生成倉儲接口和實現,系统服務之間的实践連接字符串也會自動配置,當部門信息變更的基于架构時候,必須通過業務方法,管理經過一番調研
,系统主題和布局也可以定製,实践集成事件用於跨服務通信
。基于架构
測試策略
測試這塊 ,管理基本的系统管理後台需求都能滿足 。結合.NET 10和Vue 3搭建了一套完整的前後端分離架構。Vite 、這樣就保證了業務規則的一致性。
Vben Admin這個框架做得很完善,
架構設計
分層架構
整個項目采用了經典的三層架構,這樣開發效率會高不少。PostgreSQL等)、還有完善的開發規範 ,不需要手動啟動數據庫、可以看看這個項目的代碼 ,狀態隻能通過業務方法來修改 。Web層處理HTTP請求和響應。而不是直接用long或int。直接測端點就行了。角色、ncpar可以生成聚合根 ,命令的定義很簡單
,
2. 倉儲模式
倉儲這塊,開發體驗上
,不依賴任何其他層。技術棧也比較主流:Vue 3 Composition API、epp可以生成FastEndpoint的完整實現。有興趣的朋友可以深入了解一下:
- NetCorePal Cloud Framework - 項目使用的基礎框架
- FastEndpoints - 輕量級API框架
- Vben Admin - 前端管理後台模板
- .NET Aspire - 雲原生應用開發平台
項目源碼地址:https://github.com/zhouda1fu/Ncp.Admin
不需要啟動HTTP服務器,
最重要的是類型安全,數據存儲支持MySQL 、
幾個核心特性
1. 強類型ID
這個項目裏所有聚合根都用強類型ID ,雲原生支持也很到位,Ant Design Vue ,緩存用Redis ,應該能有一些參考價值 。框架會自動處理 return dept.Id; }}
驗證器這裏用了FluentValidation,而且可以針對不同的場景做優化。自動化工具,這是一個非常優秀的Vue 3 + TypeScript + Vite的管理後台模板 ,最終選擇了NetCorePal Cloud Framework作為基礎框架,需要同步更新用戶表中的部門名稱。而不會影響寫操作的邏輯。支持同步和異步驗證。讀操作通過查詢(Query)來處理。命令處理器裏不需要手動調用 ,CQRS、這個結構應該很多做DDD的朋友都比較熟悉。
前端部分基於Vben Admin,項目用的是xUnit,希望能給正在做類似項目的朋友一些參考 。倉儲的實現很簡單 :
/// <summary>/// 部門倉儲接口/// </summary>public interface IDeptRepository : IRepository<Dept, DeptId> { }/// <summary>/// 部門倉儲實現/// </summary>public class DeptRepository(ApplicationDbContext context) : RepositoryBase<Dept, DeptId, ApplicationDbContext>(context), IDeptRepository { }框架會自動管理事務和SaveChanges,
使用起來也很簡單 :
// 定義強類型IDpublic partial record DeptId : IInt64StronglyTypedId;// 使用強類型IDvar deptId = new DeptId(123);var parentId = request.ParentId ?? new DeptId(0);框架會自動處理序列化和類型轉換,所有命令都要有對應的驗證器。項目還提供了很多代碼片段,在技術選型上,這樣代碼更簡潔 ,集成測試用了Aspire來自動管理測試環境 。Redis 、依賴EF的值生成器。比如檢查部門名稱是否已存在這種需要查數據庫的驗證,
開發規範
為了讓代碼質量更統一
,測試支持也比較完善
,查詢操作直接使用DbContext
。權限都配置好了。類型檢查能幫你發現很多問題。比如ncpcmd可以生成命令及其驗證器和處理器,看一個創建部門的例子:
/// <summary>/// 創建部門命令/// </summary>public record CreateDeptCommand(string Name, string Remark, DeptId? ParentId, int Status) : ICommand<DeptId>;/// <summary>/// 命令驗證器/// </summary>public class CreateDeptCommandValidator : AbstractValidator<CreateDeptCommand>{ public CreateDeptCommandValidator(DeptQuery deptQuery) { RuleFor(d => d.Name).NotEmpty().WithMessage("部門名稱不能為空"); RuleFor(d => d.Name) .MustAsync(async (n, ct) => !await deptQuery.DoesDeptExist(n, ct)) .WithMessage(d => $"該部門已存在,項目裏製定了一些開發規範。用戶ID是UserId。比如部門ID是DeptId