Dddify:给 ASP.NET Core 项目一套轻量、清晰、可落地的 DDD 基础设施

简介

在 .NET 项目里实践 DDD,最难的往往不是写一个聚合根,也不是引入 EF Core,而是把领域模型、应用编排、持久化、验证、事务、异常响应这些东西自然地接起来。

太轻了,团队会反复写样板代码;太重了,又容易被框架本身的约定和模块体系牵着走。

Dddify 想解决的正是这个中间地带:它不是一个大而全的应用框架,而是一个面向现代 ASP.NET Core 应用的轻量级 DDD 集成框架。它基于 MediatR、FluentValidation、Scrutor、Mapster 和 EF Core 等成熟生态,提供一组围绕 DDD 与 Clean Architecture 的基础能力,让团队把更多精力放在业务建模上。

Dddify 的定位

Dddify 的核心定位可以概括为一句话:

ASP.NET Core 项目提供轻量、可组合、贴近原生生态的 DDD 基础设施。

它推荐典型的四层结构:

text 复制代码
Domain          领域模型、聚合、值对象、领域事件、仓储契约
Application     命令、查询、验证器、处理器、DTO、应用编排
Infrastructure  EF Core、仓储实现、外部服务、迁移配置
Web             HTTP 入口、启动配置、表现层模型

这种结构并不新鲜,但 Dddify 的价值在于:它把这套结构中最容易重复接线的部分封装好了,同时又没有强行接管整个应用。

它提供了什么

Dddify 内置了一组常用 DDD 基础类型,包括:

  • AggregateRoot<TKey>:聚合根基类
  • Entity<TKey>:实体基类
  • ValueObject:值对象基类
  • IDomainEvent:领域事件契约
  • IRepository<TEntity, TKey>:仓储契约
  • DomainException / AppException:领域与应用异常
  • 审计、软删除、并发戳等接口与基类

在应用层,它通过 MediatR 组织命令和查询:

csharp 复制代码
public record CreateTodoCommand(
    string Title,
    string? Description,
    TodoPriority Priority,
    DateTime? DueDate) : ICommand<Guid>;

命令处理器只负责编排用例:校验外部条件、创建或加载聚合、调用领域行为、保存结果。真正的业务规则仍然留在领域模型里。

在示例项目 TodoApp 中,Todo 聚合通过方法表达业务动作:

csharp 复制代码
public void Complete(DateTime completedAt)
{
    EnsureNotDeleted();

    if (Status == TodoStatus.Completed)
    {
        return;
    }

    Status = TodoStatus.Completed;
    CompletedAt = completedAt;
}

这比在 handler 里直接改状态更清晰,也更符合 DDD 对"不变量由聚合维护"的要求。

应用层:命令、查询、验证和工作单元

Dddify 默认集成了两个非常实用的 MediatR 管道行为:

  • ValidationBehavior<,>:执行 FluentValidation 验证
  • UnitOfWorkBehavior<,>:为命令请求提供工作单元与事务边界

这意味着应用层可以写得很干净。比如创建 Todo 时,验证器负责请求级规则:

csharp 复制代码
public class CreateTodoCommandValidator : AbstractValidator<CreateTodoCommand>
{
    public CreateTodoCommandValidator()
    {
        RuleFor(c => c.Title)
            .NotEmpty()
            .MaximumLength(Todo.TitleMaxLength);

        RuleFor(c => c.Priority)
            .NotNull()
            .IsInEnum();
    }
}

handler 则负责编排:

csharp 复制代码
public async Task<Guid> Handle(CreateTodoCommand command, CancellationToken cancellationToken)
{
    if (await todoRepository.AnyAsync(c => c.Title == command.Title, cancellationToken))
    {
        throw new TodoTitleDuplicateException(command.Title);
    }

    var todo = new Todo(
        guidGenerator.Create(),
        command.Title,
        command.Description,
        command.Priority,
        command.DueDate);

    await todoRepository.AddAsync(todo, cancellationToken);

    return todo.Id;
}

保存和事务不需要每个 handler 手写。启用 AddDbContextWithUnitOfWork<TContext>() 后,写命令会自动进入工作单元管道。

EF Core 集成:不只是注册 DbContext

Dddify 对 EF Core 的集成不只是帮你注册一个 DbContext。它还提供:

  • 工作单元
  • 仓储基类
  • 保存拦截器
  • 审计字段自动填充
  • 软删除转换
  • 并发戳刷新
  • 领域事件分发
  • 分页、条件查询等查询扩展

典型配置非常直接:

csharp 复制代码
builder.Services.AddDddify(cfg =>
{
    cfg.AddDbContextWithUnitOfWork<ApplicationDbContext>(options =>
    {
        options.UseSqlite(builder.Configuration.GetConnectionString("Default"));
    });
});

DbContext 中可以应用默认约定:

csharp 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
    modelBuilder.ApplyDefaultConventions();

    base.OnModelCreating(modelBuilder);
}

这样,软删除、并发戳等约定就可以跟领域接口自然衔接起来。

统一 API 响应与异常映射

对 Web API 项目来说,Dddify 还提供了 API 结果包装能力:

csharp 复制代码
builder.Services.AddDddify(cfg =>
{
    cfg.AddApiResultWrapping();
});

启用后,成功响应、业务异常、验证异常、并发冲突和未知异常都可以转换为统一结构:

json 复制代码
{
  "success": false,
  "errorCode": "todo_title_duplicate",
  "errorMessage": "todo_title_duplicate",
  "traceId": "..."
}

这对前后端协作很友好。业务异常可以通过稳定错误码表达问题,错误码也可以作为本地化资源 key。

轻量,但不是简陋

Dddify 的一个重要取舍是:它保留 ASP.NET Core 原生组合方式。

它不会强制你使用某个项目模板,不接管认证授权,不绑定 UI,不要求复杂模块系统。你仍然可以按项目实际情况选择 Razor Pages、Web API、Minimal API,或者已有的基础设施。

它更像是一套"DDD 落地工具箱":

  • 你需要领域建模,它给你聚合、实体、值对象、领域事件。
  • 你需要应用编排,它给你命令、查询、处理器和管道行为。
  • 你需要持久化,它给你 EF Core 工作单元和仓储基类。
  • 你需要工程规范,它帮你减少重复接线。
  • 你想保留灵活性,它不强行把项目塞进一个巨大的框架体系。

适合什么项目

Dddify 特别适合这些场景:

  • 中小型 ASP.NET Core 业务系统
  • 业务逻辑复杂的单体应用
  • 希望实践 DDD 但不想引入重型框架的团队
  • 已有项目想渐进式引入命令、查询、工作单元和领域事件
  • 业务规则会持续演进,需要清晰领域边界的系统

如果你的项目需要完整的多租户、权限、后台管理、模块市场和预构建业务模块,ABP 这类完整框架可能更合适。

但如果你想要的是"保留 ASP.NET Core 原生体验,同时少写一堆基础设施代码",Dddify 的方向就很舒服。

从 TodoApp 看落地方式

仓库中的 TodoApp 示例展示了完整的四层实践:

text 复制代码
TodoApp.Domain
TodoApp.Application
TodoApp.Infrastructure
TodoApp.Web

它围绕一个 Todo 聚合展开,包含:

  • 聚合建模
  • 命令和查询
  • DTO
  • FluentValidation 验证器
  • 领域事件
  • EF Core + SQLite 持久化
  • Razor Pages UI

示例刻意保持小而聚焦。它不是为了炫技,而是为了让你快速看懂:Dddify 希望项目代码如何分层、如何流动、如何把业务规则放回领域模型。

生态延伸:Dddify Admin

除了核心框架和 TodoApp 示例,Dddify 官方还提供了配套的中后台项目:https://github.com/esofar/dddify-admin

Dddify Admin 基于 Dddify 与 Ant Design Pro 构建,面向真实企业后台场景,提供更完整的工程化实践,目前仍在持续开发中。

相比偏入门示例的 TodoApp,Dddify Admin 更接近真实项目开发,也体现了 Dddify 从基础框架向业务系统脚手架的生态延伸。

总结

Dddify 的价值,不在于发明一套全新的架构概念,而在于把 .NET 生态里成熟的工具,以 DDD 和 Clean Architecture 的方式组织起来。

它让你不用从零搭建:

  • MediatR 注册
  • FluentValidation 管道
  • Mapster 配置
  • Scrutor 扫描
  • EF Core 工作单元
  • 领域事件分发
  • 审计与软删除
  • API 响应包装

同时,它又足够克制,不会替你决定整个应用应该长什么样。

对于想在 ASP.NET Core 中认真落地 DDD 的团队来说,Dddify 是一个很有亲和力的起点:轻量、清晰、贴近原生生态,也足够务实。

鸣谢

Dddify 在设计和实现过程中参考了社区中多个优秀开源项目的实践经验,特别感谢:

这些项目在 .NET 领域建模、应用分层、CQRS、基础设施组织和 Clean Architecture 实践方面都提供了很有价值的参考。

相关推荐
Coder_Shenshen4 小时前
【基于LibUA库的OPC UA服务器与客户端Demo——协议解析与Bug修复实践】
网络·c#·bug
信必诺5 小时前
C# —— VS2022配置终端程序跨平台发布方法(部署Ubuntu22.04举例,详细多图)
ubuntu·c#·跨平台部署
我是唐青枫5 小时前
C#.NET YARP 跨域配置详解:网关统一处理 CORS
开发语言·c#·.net
lzhdim5 小时前
C#性能优化技巧
开发语言·性能优化·c#
weixin_428005305 小时前
C#调用 AI学习从0开始-第1阶段(基础与工具)-第5天完善请求结构
windows·学习·c#·ai请求结构
He BianGu5 小时前
【项目】WPF VisionMaster 4.0 项目介绍和开发文档
c#·wpf·流程图·开发文档·机器视觉·visionmaster
莫生灬灬5 小时前
NewEmoji 93个组件演示,支持emoji,支持易语言/火山/C#/Python
开发语言·python·c#
叫我少年19 小时前
C#基础数据类型
c#·数据类型
唐青枫20 小时前
C#.NET YARP 跨域配置详解:网关统一处理 CORS
c#·.net