I'm new to DDD and right now I'm in the process of implementing user registration.
Basically the flow is:
I'm having some doubts regarding where I place IdGeneratorService
class and BCryptService
class. Currently both of them have an Interface in Domain layer: src/Domain/Model/Services
. Their implementation is residing inside my Infrastructure layer: src/Infrastructure/Services
. They are also both being called inside the User domain model:
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);
}
This is being called by my controller:
[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;
}
I feel like calling the IdGenerator and BCrypt inside domain model is bad practice, because from what I understand the Domain layer cannot know about the Infrastructure layer, so I'm not really sure how I go about this. Any other help/suggestions regarding other implementations based on what you understood here is greatly appreciated.
It is a good practice to introduce an intermediate "Application Service" layer between the Controller and the Domain Layer.
The App Service will be responsible for invoking the (injected) infrastructure services, calling the domain layer and also persisting/loading necessary data. The Controller's responsibility is only to gather the request params, ensure authentication (if needed), and then make the call to the Application Service method.
Application Services are the direct clients of the domain model and act as intermediaries to coordinate between the external world and the domain layer. They are responsible for handling infrastructure concerns like ID Generation, Transaction Management, Encryption, etc. Such responsibilities are not concerns of the Controller layer either.
App services also typically do task coordination for APIs (one service method per API). When using an ACID database, the same Services also control transactions, ensuring that model state transitions are atomically persisted.
In your specific example, the App Service would be responsible for invoking the IdGeneratorService and BCryptService, getting the output and sending them as parameters to the domain layer. As far as the Domain layer is concerned, it does need to know how exactly the ID or the password were generated - those are not domain concerns. So it happily stays oblivious to these infrastructure aspects and only burdens itself with the tasks of User Behavior.