Value Objects are objects that describe descriptive aspects of the domain with no conceptual identity. In TaskHub.Shared, they are used to wrap primitive types and enforce validation.
Email and a string.Email object can only be created if it contains a valid email address.Email.GetDomain()) live with the data.The TaskHub.Shared.ValueObjects module includes many common types:
Email, PhoneNumber, FirstName, LastName, FullName.UserId, ClientId, JobId (Guid wrappers).LatLng (Coordinates).Title, Text, Comment.public record User(UserId Id, Email Email, FullName Name) : AggregateBase<UserId>(Id);
// Usage in a Command
public record RegisterUserCommand(string Email, string FirstName, string LastName) : ICommand;
// Usage in a Handler
public async Task<Result> HandleAsync(RegisterUserCommand cmd, CancellationToken ct)
{
// Validation happens during instantiation
var email = new Email(cmd.Email);
var name = new FullName(cmd.FirstName, cmd.LastName);
var user = new User(UserId.New(), email, name);
// ...
}
TaskHub.Shared provides converters to ensure Value Objects are correctly handled by:
builder.Property(x => x.Email)
.HasConversion(x => x.Value, x => new Email(x))
.HasMaxLength(256);
If you need a custom value object, follow this pattern:
public record MyValueObject
{
public string Value { get; init; }
public MyValueObject(string value)
{
if (string.IsNullOrWhiteSpace(value)) throw new ValueObjectException("Cannot be empty");
Value = value;
}
public static implicit operator string(MyValueObject obj) => obj.Value;
}