Implement environment-aware dependency injection to resolve EF Core provider conflict in Integration Tests. The issue was caused by both PostgreSQL and InMemory providers being registered in the same service provider. Changes: - Modified Identity Module DependencyInjection to skip PostgreSQL DbContext registration in Testing environment - Modified ProjectManagement Module ModuleExtensions with same environment check - Updated Program.cs to pass IHostEnvironment to both module registration methods - Added Microsoft.Extensions.Hosting.Abstractions package to Identity.Infrastructure project - Updated ColaFlowWebApplicationFactory to set Testing environment and register InMemory databases - Simplified WebApplicationFactory by removing complex RemoveAll logic Results: - All 31 Integration Tests now run (previously only 1 ran) - No EF Core provider conflict errors - 23 tests pass, 8 tests fail (failures are business logic issues, not infrastructure) - Production environment still uses PostgreSQL as expected 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
ColaFlow API
ColaFlow 后端 API 服务 - 基于 .NET 9 的 Modular Monolith + Clean Architecture + DDD + CQRS 实现。
架构亮点
- Modular Monolith Architecture - 模块化单体架构,清晰的模块边界
- Clean Architecture - 四层架构设计(Domain → Application → Infrastructure → API)
- Domain-Driven Design (DDD) - 领域驱动设计(战术模式)
- CQRS - 命令查询职责分离(MediatR)
- Event Sourcing - 事件溯源(用于审计日志)
- Architecture Testing - 自动化架构测试(NetArchTest)
技术栈
- .NET 9 - 最新的 .NET 平台
- Entity Framework Core 9 - ORM
- PostgreSQL 16+ - 主数据库
- Redis 7+ - 缓存和会话管理
- MediatR - 中介者模式(CQRS 和模块间通信)
- xUnit - 单元测试框架
- NetArchTest.Rules - 架构测试
- Testcontainers - 集成测试
项目结构(模块化单体)
colaflow-api/
├── src/
│ ├── ColaFlow.API/ # API 层(统一入口)
│ │ └── Program.cs # 模块注册和启动
│ │
│ ├── Modules/ # 业务模块
│ │ ├── ProjectManagement/ # 项目管理模块
│ │ │ ├── ColaFlow.Modules.PM.Domain/
│ │ │ │ ├── Aggregates/ # Project, Epic, Story, Task
│ │ │ │ ├── ValueObjects/ # ProjectId, ProjectKey, etc.
│ │ │ │ ├── Events/ # Domain Events
│ │ │ │ └── Exceptions/ # Domain Exceptions
│ │ │ ├── ColaFlow.Modules.PM.Application/
│ │ │ │ ├── Commands/ # CQRS Commands
│ │ │ │ ├── Queries/ # CQRS Queries
│ │ │ │ └── DTOs/ # Data Transfer Objects
│ │ │ ├── ColaFlow.Modules.PM.Infrastructure/
│ │ │ │ ├── Persistence/ # EF Core Configurations
│ │ │ │ └── Repositories/ # Repository Implementations
│ │ │ └── ColaFlow.Modules.PM.Contracts/
│ │ │ └── Events/ # Integration Events
│ │ │
│ │ ├── Workflow/ # 工作流模块(待实现)
│ │ ├── UserManagement/ # 用户管理模块(待实现)
│ │ ├── Notifications/ # 通知模块(待实现)
│ │ ├── Audit/ # 审计模块(待实现)
│ │ └── AI/ # AI 模块(待实现)
│ │
│ ├── Shared/ # 共享内核
│ │ └── ColaFlow.Shared.Kernel/
│ │ ├── Common/ # Entity, ValueObject, AggregateRoot
│ │ ├── Events/ # DomainEvent
│ │ └── Modules/ # IModule 接口
│ │
│ └── [Legacy - To be removed] # 旧的单体结构(迁移中)
│ ├── ColaFlow.Domain/
│ ├── ColaFlow.Application/
│ └── ColaFlow.Infrastructure/
│
├── tests/
│ ├── ColaFlow.ArchitectureTests/ # 架构测试(模块边界)
│ ├── ColaFlow.Domain.Tests/ # 领域层单元测试
│ ├── ColaFlow.Application.Tests/ # 应用层单元测试
│ └── ColaFlow.IntegrationTests/ # 集成测试
└── ColaFlow.sln
Modular Monolith 架构
模块边界规则
┌────────────────────────────────────────────────────┐
│ ColaFlow.API (Entry Point) │
└─────────────────┬──────────────────────────────────┘
│
┌─────────────┴─────────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ PM │ │ Workflow │ ... (其他模块)
│ Module │◄─────────►│ Module │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────────────────────────────┐
│ Shared.Kernel (Common Base) │
└─────────────────────────────────────┘
模块通信规则
- 禁止直接引用其他模块的 Domain 实体
- 允许通过 MediatR 查询其他模块(Application Service Integration)
- 允许通过 Domain Events 解耦通信(Event-Driven)
- 使用 Contracts 项目定义模块对外接口
架构测试
项目包含自动化架构测试,确保模块边界被严格遵守:
dotnet test tests/ColaFlow.ArchitectureTests
测试内容:
- Domain 层不依赖 Application 和 Infrastructure
- Domain 层只依赖 Shared.Kernel
- 模块间不直接引用其他模块的 Domain 实体
- AggregateRoot 正确继承
- ValueObject 是不可变的(sealed)
Clean Architecture 层级依赖
每个模块内部仍然遵循 Clean Architecture:
Module Structure:
API/Controllers ──┐
├──> Application ──> Domain
Infrastructure ───┘
依赖规则:
- Domain 层:仅依赖 Shared.Kernel(无其他依赖)
- Application 层:依赖 Domain 和 Contracts
- Infrastructure 层:依赖 Domain 和 Application
- API 层:依赖所有层
快速开始
前置要求
- .NET 9 SDK
- Docker Desktop(用于 PostgreSQL 和 Redis)
- IDE:Visual Studio 2022 / JetBrains Rider / VS Code
1. 安装依赖
cd colaflow-api
dotnet restore
2. 启动数据库(使用 Docker)
从项目根目录启动:
cd ..
docker-compose up -d postgres redis
3. 运行数据库迁移
# 创建迁移(Infrastructure 层完成后)
dotnet ef migrations add InitialCreate --project src/ColaFlow.Infrastructure --startup-project src/ColaFlow.API
# 应用迁移
dotnet ef database update --project src/ColaFlow.Infrastructure --startup-project src/ColaFlow.API
4. 运行 API
cd src/ColaFlow.API
dotnet run
API 将运行在:
- HTTP:
http://localhost:5000 - HTTPS:
https://localhost:5001 - Swagger/Scalar:
https://localhost:5001/scalar/v1
5. 运行测试
# 运行所有测试
dotnet test
# 运行单元测试
dotnet test --filter Category=Unit
# 运行集成测试
dotnet test --filter Category=Integration
# 生成覆盖率报告
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
开发指南
Domain Layer 开发
聚合根示例:
public class Project : AggregateRoot
{
public ProjectId Id { get; private set; }
public string Name { get; private set; }
// 工厂方法
public static Project Create(string name, string description, UserId ownerId)
{
var project = new Project
{
Id = ProjectId.Create(),
Name = name,
OwnerId = ownerId
};
project.AddDomainEvent(new ProjectCreatedEvent(project.Id, project.Name));
return project;
}
// 业务方法
public void UpdateDetails(string name, string description)
{
Name = name;
Description = description;
AddDomainEvent(new ProjectUpdatedEvent(Id));
}
}
Application Layer 开发(CQRS)
Command 示例:
public sealed record CreateProjectCommand : IRequest<ProjectDto>
{
public string Name { get; init; }
public string Description { get; init; }
}
public sealed class CreateProjectCommandHandler : IRequestHandler<CreateProjectCommand, ProjectDto>
{
public async Task<ProjectDto> Handle(CreateProjectCommand request, CancellationToken cancellationToken)
{
// 1. 创建聚合
var project = Project.Create(request.Name, request.Description, currentUserId);
// 2. 保存
await _repository.AddAsync(project, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
// 3. 返回 DTO
return _mapper.Map<ProjectDto>(project);
}
}
Query 示例:
public sealed record GetProjectByIdQuery : IRequest<ProjectDto>
{
public Guid ProjectId { get; init; }
}
public sealed class GetProjectByIdQueryHandler : IQueryHandler<GetProjectByIdQuery, ProjectDto>
{
public async Task<ProjectDto> Handle(GetProjectByIdQuery request, CancellationToken cancellationToken)
{
var project = await _context.Projects
.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == request.ProjectId, cancellationToken);
return _mapper.Map<ProjectDto>(project);
}
}
API Layer 开发
Controller 示例:
[ApiController]
[Route("api/v1/[controller]")]
public class ProjectsController : ControllerBase
{
private readonly IMediator _mediator;
[HttpPost]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status201Created)]
public async Task<IActionResult> CreateProject([FromBody] CreateProjectCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(GetProject), new { id = result.Id }, result);
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status200OK)]
public async Task<IActionResult> GetProject(Guid id)
{
var result = await _mediator.Send(new GetProjectByIdQuery { ProjectId = id });
return Ok(result);
}
}
测试策略
测试金字塔
- 70% 单元测试 - Domain 和 Application 层
- 20% 集成测试 - API 端点测试
- 10% E2E 测试 - 关键用户流程
单元测试示例
public class ProjectTests
{
[Fact]
public void Create_WithValidData_ShouldCreateProject()
{
// Arrange
var name = "Test Project";
var ownerId = UserId.Create();
// Act
var project = Project.Create(name, "Description", ownerId);
// Assert
project.Should().NotBeNull();
project.Name.Should().Be(name);
project.DomainEvents.Should().ContainSingle(e => e is ProjectCreatedEvent);
}
}
集成测试示例
public class ProjectsControllerTests : IntegrationTestBase
{
[Fact]
public async Task CreateProject_WithValidData_ShouldReturn201()
{
// Arrange
var command = new CreateProjectCommand { Name = "Test", Description = "Test" };
// Act
var response = await _client.PostAsJsonAsync("/api/v1/projects", command);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
var project = await response.Content.ReadFromJsonAsync<ProjectDto>();
project.Should().NotBeNull();
}
}
代码质量
覆盖率要求
- 最低要求:80%
- 目标:90%+
- 关键路径:100%
代码规范
- 遵循 C# 编码规范
- 使用 private 构造函数 + 工厂方法
- 所有 public 方法必须有 XML 注释
- 所有业务逻辑必须有单元测试
NuGet 包版本
Domain Layer
- 无外部依赖
Application Layer
- MediatR 13.1.0
- FluentValidation 12.0.0
- AutoMapper 15.1.0
Infrastructure Layer
- Microsoft.EntityFrameworkCore 9.0.10
- Npgsql.EntityFrameworkCore.PostgreSQL 9.0.4
- StackExchange.Redis 2.9.32
API Layer
- Serilog.AspNetCore 9.0.0
- Scalar.AspNetCore 2.9.0
Test Projects
- xUnit 2.9.2
- FluentAssertions 8.8.0
- Moq 4.20.72
- Testcontainers 4.x
环境变量
创建 src/ColaFlow.API/appsettings.Development.json:
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5432;Database=colaflow;Username=colaflow;Password=colaflow_password",
"Redis": "localhost:6379,password=colaflow_redis_password"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
API 文档
启动应用后,访问:
- Scalar UI:
https://localhost:5001/scalar/v1 - OpenAPI JSON:
https://localhost:5001/openapi/v1.json
相关文档
下一步开发任务
Infrastructure Layer(进行中)
- 配置 EF Core DbContext
- 创建 Entity Configurations
- 生成数据库 Migrations
- 实现 Repository 和 Unit of Work
Application Layer(待开发)
- 实现 CQRS Commands
- 实现 CQRS Queries
- 配置 MediatR Pipeline Behaviors
- 实现 FluentValidation Validators
API Layer(待开发)
- 实现 REST API Controllers
- 配置 OpenAPI/Scalar
- 实现异常处理中间件
- 配置 JWT 认证
测试(待开发)
- 编写 Domain 单元测试(≥80% 覆盖率)
- 编写 Application 单元测试
- 编写 API 集成测试
License
MIT License
团队
ColaFlow Development Team
当前状态: 🟡 Domain Layer 完成,Infrastructure 和 Application 层开发中
最后更新: 2025-11-02