使用 DDD 为用户域模型生成 ID 和散列密码的最佳方法

Best approach for Id generation and password hashing using DDD for User Domain model

我是 DDD 的新手,现在我正在实施用户注册。

基本上流程是:

  1. 控制器收到请求
  2. 将从客户端接收到的数据映射到用户域模型。
  3. 将用户域模型映射到 EF 核心实体模型。
  4. 使用 EF-Core 将用户添加到数据库。

我对 IdGeneratorService class 和 BCryptService class 的位置有一些疑问。目前它们在域层都有一个接口:src/Domain/Model/Services。它们的实现驻留在我的基础设施层中:src/Infrastructure/Services。它们也在用户域模型中被调用:

public class User
{
    private User(
        long id, 
        string name, 
        string lastName, 
        string contactPhone, 
        string contactEmail, 
        string userName, 
        string password)
    {
        Id = id;
        Name = name;
        LastName = lastName;
        ContactPhone = contactPhone;
        ContactEmail = contactEmail;
        UserName = userName;
        Password = password;
    }

    public IEnumerable<Role> Type { get; set; }

    public static async Task<User> ConstructAsync(
        string name, string lastName, 
        string contactPhone, string contactEmail, 
        string userName, string password, 
        IIdGeneratorService<long> idGeneratorService, IBCryptService bCryptService)
    {
        var id = await idGeneratorService.GenerateAsync();

        password = bCryptService.HashPassword(password);

        return new User(id, name, lastName, contactPhone, contactEmail, userName, password); 
    } 

这是由我的控制器调用的:

[HttpPost("[Action]")]
public async Task<IActionResult> Create([FromBody] UserModel userModel)
{
    var user = 
        await DomainUser.ConstructAsync(
            userModel.Name, userModel.LastName,
            userModel.ContactPhone, userModel.ContactEmail,
            userModel.UserName, userModel.Password,
            _idGeneratorService, _bCryptService);

    await _userRepository.AddAsync(user);

    return sampleResponse;
}

我觉得在域模型中调用 IdGenerator 和 BCrypt 是一种不好的做法,因为据我所知,域层无法了解基础结构层,所以我不太确定我该怎么做。非常感谢任何其他 help/suggestions 关于基于您在此处理解的内容的其他实现。

在控制器和域层之间引入一个中间 "Application Service" 层是一个很好的做法。

App Service 将负责调用(注入的)基础设施服务,调用域层以及 persisting/loading 必要的数据。控制器的职责只是收集请求参数,确保身份验证(如果需要),然后调用应用程序服务方法。

应用服务是领域模型的直接客户,充当协调外部世界和领域层之间的中介。他们负责处理基础设施问题,例如 ID 生成、事务管理、加密等。这些职责也不是控制器层的问题。

应用程序服务通常还会在 API 秒内进行任务协调(每个 API 一个服务方法)。使用 ACID 数据库时,相同的服务还控制事务,确保模型状态转换以原子方式持久化。

在您的具体示例中,应用服务将负责调用 IdGeneratorService 和 BCryptService,获取输出并将它们作为参数发送到域层。就域层而言,它确实需要知道 ID 或密码是如何生成的——这些与域无关。所以它很高兴地忽略了这些基础设施方面,只为用户行为的任务增加了负担。