I'm tasked with developing an application which is going to track what an end user does in a session.
My application doesn't handle user registration or anything related to user. The user management is a different bounded context(a separate micro service in my case.) But my application would need to identify an user from a user card(my application would receive the card information.). I would need to call the User micro service with the card information to get user details back. And with the details received, I would need to apply business rules(these rules are part of my domain) to verify if this user can create a session or not.
This is my handler in the Application layer,
public async Task<int> Handle(CreateSessionCommand request, CancellationToken cancellationToken)
{
//Get Player details from third party service from the Infrastructure layer
var playerSearch = await _playerService.GetPlayerByCardAsync(request.CardTrack);
//Create a domain object from the search details.
Player player = new Player(playerSearch.Id, playerSearch.Name, playerSearch.Age);
//Apply domain rules
if (player.CanCreatePlayerSession())
{
//
}
return 0;
}
This is my Player domain entity,
public class Player
{
public Player(int id, string name, int age)
{
Id = id;
Name = name;
Age = age;
}
public int Id { get; private set; }
public string Name { get; private set; } = string.Empty;
public int Age { get; private set; }
public bool CanCreatePlayerSession()
{
return this.Age > 18;
}
}
Is creating a domain object from a Infrastructure service a good DDD approach? Are there any better ways of doing something similar?
Consider the following: is Player
owned by your domain or by some external system's domain?
If your system owns Player
, the latter should basically reflect GetPlayerByCardAsync's response (PlayerService constructs full player object for you, probably by calling another api or directing querying a storage).
But also if Player
is owned by an external system, or by a legacy system within your domain, you should count on that system to construct this object.
So we can see that in all above cases a somewhat external component, encapsulated inside an infrastructure service, is responsible for the construction of Player
. And deserialization is performed directly inside that infrastructure service.
But when dealing with external/legacy systems, it is sometimes necessary to perform adaptations (the anti-corruption layer pattern). From your code sample I can assume that you have that need, since you present the method CanCreatePlayerSession
. That actually means that you have two separate domain objects for a player: the one that returns from PlayerService, and the one constructed by you. I would recommend to use more accurate semantics, e.g. CardPlayer
and SessionPlayer
.
The instruction to construct SessionPlayer
object, however, should, in line with your code sample, come from the application layer, as it is part of application flow.