跳到主要内容
版本:3.0.0

Services 与 Contract

这页讲的是业务层怎么落。

先用最常见的理解方式就够:

  • Contract 放接口
  • Services 写实现
  • Dto 放传输对象
  • Controller 调契约

先把边界分清

Contract 负责定义服务边界。
Services 负责把业务流程串起来。

最稳的理解方式是:

  • Controller 不写业务
  • Service 不直接碰数据库底层
  • Repository 负责数据访问

一个最小落地方式

1. 在 Component.deps.json 里启用 BusinessServices

{
"Components": {
"Services": [
"BusinessServices"
]
}
}

2. 契约接口继承 IBusinessService

public interface IUserContract : IBusinessService
{
Task<bool> ChangeUser(int id);
Task<bool> ChangeUserStatus(int id, int statusCode);
}

3. Service 实现契约

public class UserService : IUserContract
{
private readonly UserRepository _userRepository;

public UserService(UserRepository userRepository)
{
_userRepository = userRepository;
}

public async Task<bool> ChangeUser(int id)
{
var user = await _userRepository.GetByIdAsync(id);
return await _userRepository.UpdateAsync(user);
}

public Task<bool> ChangeUserStatus(int id, int statusCode)
{
return Task.FromResult(true);
}
}

4. Controller 注入契约

public class UserController : ApiControllerBase
{
private readonly IUserContract _userService;

public UserController(IUserContract userService)
{
_userService = userService;
}
}

这一层现在怎么理解更合适

如果项目不大,把 Services 理解成“业务服务层”就够了。
如果项目开始变复杂,就把它看成一个大的 DDD 业务领域层。

也就是说,Services 下面可以继续拆:

  • 应用服务
  • 领域服务
  • Rules
  • Strategies

但有一条别变:

数据访问还是收口到 Repository

一个常见的组织方式

XXX.Services
├── PatientSettlement
│ ├── PatientSettlementService.cs
│ ├── SettlementRuleDomainService.cs
│ ├── Rules
│ └── Strategies
├── PrescriptionAudit
│ ├── PrescriptionAuditService.cs
│ ├── AuditRuleDomainService.cs
│ └── Rules

怎么判断一个类该放哪

可以先问自己两个问题:

  1. 这个类是不是在组织一次完整业务流程?
    如果是,更像应用服务。

  2. 这个类拿掉仓储、事务、DTO 之后,还像一段独立业务规则吗?
    如果是,更像领域服务。

ServiceResultPagedResult 怎么选

PagedResult<T>

分页查询就用它。

ServiceResult<T>

只有在分支复杂、需要统一包装业务结果时再用。
能直接返回 DTO、列表、分页结果的时候,先别把它包得太重。

这一层最容易写错的地方

  • 契约接口没有继承 IBusinessService
  • BusinessServices 没开
  • Service 直接去碰 IFreeSql
  • 把 Controller 的请求模型直接塞进业务层逻辑
  • 明明能直接返回 DTO,却把所有东西都包成 ServiceResult

最后记一条

Services 这一层最重要的,不是“类名是不是漂亮”,而是边界是不是清楚:

  • Service 负责业务流程
  • Repository 负责数据访问
  • Controller 负责接口入口

只要这条没乱,后面怎么继续 DDD 化都好调整。