Validated.Primitives.Domain
1.1.28
See the version list below for details.
dotnet add package Validated.Primitives.Domain --version 1.1.28
NuGet\Install-Package Validated.Primitives.Domain -Version 1.1.28
<PackageReference Include="Validated.Primitives.Domain" Version="1.1.28" />
<PackageVersion Include="Validated.Primitives.Domain" Version="1.1.28" />
<PackageReference Include="Validated.Primitives.Domain" />
paket add Validated.Primitives.Domain --version 1.1.28
#r "nuget: Validated.Primitives.Domain, 1.1.28"
#:package Validated.Primitives.Domain@1.1.28
#addin nuget:?package=Validated.Primitives.Domain&version=1.1.28
#tool nuget:?package=Validated.Primitives.Domain&version=1.1.28
Validated Primitives
A .NET library that provides strongly-typed, self-validating primitive value objects to eliminate primitive obsession and enforce domain constraints at compile-time.
Packages
This repository contains two NuGet packages:
📦 Validated.Primitives (Core)
The foundation library providing low-level validated primitive value objects.
dotnet add package Validated.Primitives
What it provides:
- Email addresses, phone numbers, URLs, IP addresses
- Postal codes with country-specific validation (30+ countries)
- Date/time value objects (DateOfBirth, FutureDate, date ranges)
- Financial primitives (Money, Percentage, CurrencyCode)
- Credit card primitives (CreditCardNumber, CreditCardSecurityNumber, CreditCardExpiration)
- Text primitives (HumanName, AddressLine, City, StateProvince)
- Validation framework and error handling
- JSON serialization support
📦 Validated.Primitives.Domain (Composition)
Higher-level domain models composed from validated primitives.
dotnet add package Validated.Primitives.Domain
What it provides:
- PersonName - Complete human name (first, last, middle) with computed properties (FullName, FormalName, Initials)
- Address - Physical mailing address with country-specific postal code validation
- ContactInformation - Email, primary/secondary phone, optional website
- CreditCardDetails - Complete payment card (number, CVV, expiration) with masking and expiration checking
Think of it as:
Validated.Primitives= LEGO bricks (EmailAddress, PhoneNumber, PostalCode)Validated.Primitives.Domain= Complete LEGO models (Address, PersonName, ContactInformation)
What are Validated Primitives?
Validated Primitives are value objects that encapsulate primitive types (strings, dates, numbers) with built-in validation rules. Instead of passing raw strings or dates throughout your application, you use strongly-typed objects that guarantee their validity.
The Problem: Primitive Obsession
// ❌ Traditional approach - primitive obsession
public class User
{
public string Email { get; set; } // Could be null, empty, or invalid
public string PhoneNumber { get; set; } // No format validation
public DateTime DateOfBirth { get; set; } // Could be in the future!
public string PostalCode { get; set; } // No country-specific validation
}
// Validation logic scattered everywhere
if (string.IsNullOrWhiteSpace(user.Email) || !IsValidEmail(user.Email))
{
throw new ArgumentException("Invalid email");
}
The Solution: Validated Primitives
// ✅ With Validated Primitives
public class User
{
public EmailAddress Email { get; set; } // Always valid or null
public PhoneNumber PhoneNumber { get; set; } // Always properly formatted
public DateOfBirth DateOfBirth { get; set; } // Always in the past
public PostalCode PostalCode { get; set; } // Country-specific validation
}
// Validation happens at creation - guaranteed valid everywhere else
var (result, email) = EmailAddress.TryCreate(userInput);
if (!result.IsValid)
{
// Handle validation errors
Console.WriteLine(result.ToBulletList());
return;
}
// email is guaranteed to be valid here
user.Email = email;
Key Benefits
- Type Safety: Compiler prevents mixing up different string types
- Self-Validating: Validation logic lives with the data
- Immutable: Value objects are records - thread-safe by default
- Explicit Intent: Code clearly communicates business rules
- Centralized Validation: No scattered validation logic
- Rich Error Messages: Detailed validation feedback
Installation
dotnet add package Validated.Primitives
Available Value Objects
📧 Email & Communication
EmailAddress- RFC 5322 compliant email format, max 256 charactersPhoneNumber- International phone number validation with country code supportWebsiteUrl- Valid HTTP/HTTPS URLs with proper scheme validation
📍 Location & Geography
PostalCode- Country-specific postal code validation for 30+ countriesCity- City names, max 100 characters, letters/spaces/hyphens/apostrophesStateProvince- State or province names, max 100 charactersAddressLine- Street address lines, max 200 characters
🌐 Network
IpAddress- Valid IPv4 or IPv6 addresses
📅 Date & Time
DateOfBirth- Must be in the past, cannot be future dateFutureDate- Must be in the future, cannot be past dateBetweenDatesSelection- Date within a specified rangeDateRange- Represents a range between two DateTimes with duration calculationDateOnlyRange- Represents a range between two DateOnly valuesTimeOnlyRange- Represents a range between two TimeOnly values
💳 Financial & Payment
Money- Monetary amounts with currency codes and precision validationSmallUnitMoney- Monetary amounts in smallest currency unit (e.g., cents)Percentage- Percentage values with configurable decimal placesCurrencyCode- ISO 4217 currency codes (USD, EUR, GBP, etc.)CreditCardNumber- Luhn-validated card numbers, 13-19 digits, rejects all-same-digit patternsCreditCardSecurityNumber- CVV/CVC security codes, 3-4 digitsCreditCardExpiration- Card expiration date with automatic 2-digit year normalization
👤 Personal Information
HumanName- Individual name parts (first, middle, last), 1-50 characters, letters/hyphens/apostrophes/spaces
API Integration Example
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpPost]
public IActionResult CreateUser([FromBody] CreateUserRequest request)
{
var (emailResult, email) = EmailAddress.TryCreate(request.Email, nameof(request.Email));
if (!emailResult.IsValid)
{
return BadRequest(emailResult.ToDictionary());
}
var (phoneResult, phone) = PhoneNumber.TryCreate(request.Phone, nameof(request.Phone));
if (!phoneResult.IsValid)
{
return BadRequest(phoneResult.ToDictionary());
}
var (postalResult, postalCode) = PostalCode.TryCreate(
request.CountryCode,
request.PostalCode,
nameof(request.PostalCode)
);
if (!postalResult.IsValid)
{
return BadRequest(postalResult.ToDictionary());
}
// Create user with validated primitives
var user = new User
{
Email = email,
Phone = phone,
PostalCode = postalCode
};
// Save user...
return Ok(user);
}
}
Using Validated.Primitives.Domain
For more complex scenarios, use the Validated.Primitives.Domain package which provides pre-built domain aggregates:
Complete User Profile Example
using Validated.Primitives.Domain;
using Validated.Primitives.ValueObjects;
// Create a complete address
var (addressResult, address) = Address.TryCreate(
street: "123 Main Street",
addressLine2: "Apt 4B",
city: "New York",
country: CountryCode.UnitedStates,
postalCode: "10001",
stateProvince: "NY"
);
// Create a person name
var (nameResult, personName) = PersonName.TryCreate(
firstName: "John",
lastName: "Doe",
middleName: "Michael"
);
// Create contact information
var (contactResult, contact) = ContactInformation.TryCreate(
countryCode: CountryCode.UnitedStates,
email: "john.doe@example.com",
primaryPhone: "+1-555-123-4567",
secondaryPhone: null,
website: "https://johndoe.com"
);
// Create credit card details
var (cardResult, card) = CreditCardDetails.TryCreate(
cardNumber: "4111 1111 1111 1111",
securityNumber: "123",
expirationMonth: 12,
expirationYear: 2025
);
if (addressResult.IsValid && nameResult.IsValid &&
contactResult.IsValid && cardResult.IsValid)
{
Console.WriteLine($"Name: {personName.FullName}");
Console.WriteLine($"Formal: {personName.FormalName}");
Console.WriteLine($"Initials: {personName.Initials}");
Console.WriteLine($"\nAddress: {address}");
Console.WriteLine($"\nContact: {contact.Email.Value}");
Console.WriteLine($"Phone: {contact.PrimaryPhone.Value}");
Console.WriteLine($"\nCard: {card.GetMaskedCardNumber()}");
Console.WriteLine($"Expires: {card.Expiration}");
Console.WriteLine($"Is Expired: {card.IsExpired()}");
}
Benefits of Domain Models
- Grouped Validation - Validate all related fields in one call
- Rich Behavior -
FullName,FormalName,Initials,GetMaskedCardNumber(),IsExpired() - Cohesive APIs - Pass
ContactInformationinstead of Email + Phone + Website separately - Guaranteed Consistency - If you have an
Address, all its parts are valid
Domain Models Available:
PersonName- FirstName + LastName + MiddleName with computed propertiesAddress- Complete mailing address with country-specific validationContactInformation- Email + Phones + WebsiteCreditCardDetails- CardNumber + CVV + Expiration with masking
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Validated.Primitives (>= 1.1.28)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Domain models including Address, ContactInformation, and PersonName types.