TooManyDataAnnotations 0.1.0
See the version list below for details.
dotnet add package TooManyDataAnnotations --version 0.1.0
NuGet\Install-Package TooManyDataAnnotations -Version 0.1.0
<PackageReference Include="TooManyDataAnnotations" Version="0.1.0" />
<PackageVersion Include="TooManyDataAnnotations" Version="0.1.0" />
<PackageReference Include="TooManyDataAnnotations" />
paket add TooManyDataAnnotations --version 0.1.0
#r "nuget: TooManyDataAnnotations, 0.1.0"
#:package TooManyDataAnnotations@0.1.0
#addin nuget:?package=TooManyDataAnnotations&version=0.1.0
#tool nuget:?package=TooManyDataAnnotations&version=0.1.0
<div align="center"> <img src="TooManyDataAnnotations/Assets/icon.png" alt="TooManyDataAnnotations icon" width="128" /> </div>
TooManyDataAnnotations 🎯
Extending .NET's System.ComponentModel.DataAnnotations with powerful, semantic validation attributes.
💡 Tip: Check the NuGet page
📖 About
TooManyDataAnnotations is a collection of custom validation attributes designed to fill the gaps in .NET's built-in DataAnnotations library. While Microsoft provides basic validators (EmailAddress, Url, Range), they lack semantic validations for modern development needs like IPv4/IPv6, Semantic Versioning, MAC Addresses, ISO 8601 Dates, and more
This library provides production-ready, strongly-typed attributes that make your DTOs, models, and APIs self-documenting and robust
✨ Key Features
| Feature | Description |
|---|---|
| ✅ Allocation-Conscious | Optimized with Span<T> and native .NET parsers where possible |
| ✅ Strongly Typed | IntelliSense support, no magic strings |
| ✅ Comprehensive Testing | Each attribute has 20+ test cases covering edge cases |
| ✅ Open Source | MIT Licensed, community contributions welcome |
| ✅ Namespace Organized | Clean separation: Network, Text, Formatting, etc. |
📦 Installation
dotnet add package TooManyDataAnnotations
🧩 Attributes by Category
🔢 Identifiers
Validates unique identifiers and URIs.
| Attribute | Purpose | Example |
|---|---|---|
[Guid] |
Valid GUID format (any version) | [Guid] public string Id { get; set; } |
[GuidV7] |
Strict GUID Version 7 only | [GuidV7] public string NewId { get; set; } |
[Uri] |
Full URI validation with scheme filtering | [Uri(UriSchemes.Https)] public string ApiEndpoint { get; set; } |
Example:
public class UserDto
{
[GuidV7] // Only v7 allowed
public string UserId { get; set; }
[Uri(UriSchemes.Http | UriSchemes.Https)]
public string Website { get; set; }
}
📝 Text
String formatting and content validation.
| Attribute | Purpose | Example |
|---|---|---|
[WebUrl] |
HTTP/HTTPS URLs (with or without scheme) | [WebUrl] public string Link { get; set; } |
[Slug] |
URL-friendly slugs (alphanumeric, hyphens) | [Slug] public string PostSlug { get; set; } |
[HexColor] |
Hex color codes (#RGB, #RRGGBB, with alpha) | [HexColor(AllowAlpha = true)] public string ThemeColor { get; set; } |
Example:
public class BlogPostDto
{
[WebUrl(RequireHttps = true)]
public string? FeaturedImage { get; set; }
[Slug(AllowNumbers = true, RequireLowerCase = true)]
public string TitleSlug { get; set; }
[HexColor]
public string AccentColor { get; set; } = "#6d4aff";
}
🌐 Network
IP addresses, MAC addresses, and port numbers
| Attribute | Purpose | Example |
|---|---|---|
[IPv4] |
IPv4 address with scope filtering | [IPv4(AllowedScopes = IPv4Scope.Private)] public string ServerIP { get; set; } |
[IPv6] |
IPv6 address (standard, compressed, mapped) | [IPv6(AllowCompressed = false)] public string IPv6Addr { get; set; } |
[MacAddress] |
MAC address formats (XX:XX:... , XX-XX:...) | [MacAddress(AllowedSeparators = MacSeparators.Colon)] public string DeviceMAC { get; set; } |
[PortNumber] |
TCP/UDP port with range filtering | [PortNumber(AllowedRanges = PortRanges.WellKnown)] public int ListenPort { get; set; } |
Enums Used:
IPv4Scope:Public,LocalA,LocalB,LocalC,Private(= LocalA | LocalB | LocalC),Loopback,LinkLocal,Multicast,Reserved,AllMacSeparators:Continuous(no separators),Colon,Dash,Dot,AnySeparator(= Colon | Dash | Dot),AllPortRanges:WellKnown(0-1023),Registered(1024-49151),Dynamic(49152-65535)
Example:
public class NetworkConfigDto
{
[IPv4(AllowedScopes = IPv4Scope.Private)]
public string GatewayIP { get; set; }
[IPv6(AllowIPv4Mapped = false)]
public string PrimaryIPv6 { get; set; }
[MacAddress(AllowedSeparators = MacSeparators.All)]
public string AdapterMAC { get; set; }
[PortNumber(AllowedRanges = PortRanges.Registered)]
public int ApplicationPort { get; set; }
}
⏱️ Formatting
Dates, versions, and structured formats.
| Attribute | Purpose | Example |
|---|---|---|
[SemanticVersion] |
SemVer 2.0.0 (e.g., 1.2.3-beta.1) | [SemanticVersion] public string LibraryVersion { get; set; } |
[IsoDateTime] |
ISO 8601 dates/times | [IsoDateTime(RequireTime = true)] public DateTime Timestamp { get; set; } |
Examples:
public class ReleaseDto
{
[SemanticVersion] // Validates "MAJOR.MINOR.PATCH[-PRE][+BUILD]"
public string Version { get; set; }
[IsoDateTime(RequireTime = true, AllowOffset = true)]
public string PublishedAt { get; set; } // e.g., "2025-06-09T14:30:00Z"
}
🏗️ Classes
Validation rules applied to entire objects/classes
| Attribute | Purpose | Example |
|---|---|---|
[RequiredAtLeastN] |
At least N of multiple properties must have a value | [RequiredAtLeastN(Minimum = 2, nameof(Phone), nameof(Email), nameof(Address))] |
[RequiredAtLeastOne] |
At least one of multiple properties must have a value | [RequiredAtLeastOne(nameof(Email), nameof(Phone))] |
[ExactlyNOf] |
Exactly N of multiple properties must have a value | [ExactlyNOf(Count = 2, nameof(CreditCard), nameof(PayPal), nameof(Cash))] |
[ExactlyOneOf] |
Exactly ONE of multiple properties must have a value (XOR) | [ExactlyOneOf(nameof(CreditCard), nameof(PayPal))] |
Note:
RequiredAtLeastOneandExactlyOneOfare convenience wrappers aroundRequiredAtLeastN(Minimum = 1) andExactlyNOf(Count = 1) respectively, with simpler default error messages
Properties:
CountEmptyStringsAsValue: Iftrue, empty strings count as "provided". Default:false
Example:
[RequiredAtLeastOne(nameof(Email), nameof(Phone), nameof(SocialHandle))]
public class ContactInfoDto
{
public string? Email { get; set; }
public string? Phone { get; set; }
public string? SocialHandle { get; set; }
}
[ExactlyOneOf(nameof(CreditCard), nameof(PayPal), nameof(BankTransfer))]
public class PaymentMethodDto
{
public string? CreditCard { get; set; } // Provide EXACTLY ONE
public string? PayPal { get; set; }
public string? BankTransfer { get; set; }
}
🗓️ Temporal
Dates and specific points of time
| Attribute | Purpose | Example |
|---|---|---|
[StartDate] |
Date must be ≤ another property's date | [StartDate] public DateTime StartDate { get; set; } |
[EndDate] |
Date must be ≥ another property's date | [EndDate] public DateTime EndDate { get; set; } |
Examples:
// By default, it will use "StartDate" and "EndDate" properties to validate
public class EventDto
{
[StartDate]
public DateTime StartDate { get; set; }
[EndDate]
public DateTime EndDate { get; set; }
}
// Or you can specify your specific properties
public class EventDto
{
[StartDate(nameof(MyEndTime))]
public DateTime MyStartTime { get; set; }
[EndDate(nameof(MyStartTime))]
public DateTime MyEndTime { get; set; }
}
⚡ Logical
Boolean validation rules — single values, collections, and class-level constraints
| Attribute | Purpose | Example |
|---|---|---|
[IsTrue] |
Value must be true |
[IsTrue] public bool AcceptedTerms { get; set; } |
[IsFalse] |
Value must be false |
[IsFalse] public bool IsDeleted { get; set; } |
[AtLeastOneTrue] |
At least one boolean in a collection/properties is true |
[AtLeastOneTrue(nameof(AgreeEmail), nameof(AgreeSms))] |
[ExactlyOneTrue] |
Exactly one boolean is true (XOR) |
[ExactlyOneTrue(nameof(OptionA), nameof(OptionB))] |
[ExactlyNTrue] |
Exactly N booleans are true |
[ExactlyNTrue(Count = 2)] public bool[] Features { get; set; } |
[MinimumTrueValues] |
At least N booleans are true |
[MinimumTrueValues(Minimum = 2)] public List<bool> Checks { get; set; } |
Note:
AtLeastOneTrueandExactlyOneTrueare convenience wrappers aroundMinimumTrueValues(Minimum = 1) andExactlyNTrue(Count = 1) respectively, with simpler default error messages
🚀 Roadmap
What's coming next? (Priority order)
-
[IsTrueAttribute]/[IsFalseAttribute]— Mandatory boolean flags -
[StartDateAttribute]/[EndDateAttribute]— Date range comparison -
[HashtagAttribute]— Social media hashtag format - NuGet package publication
- Source Generator for AOT-compatible class-mode validation
- Additional attributes based on community feedback
🤝 Contributing
We welcome contributions! Please read our Contributor Guide before submitting PRs
How to Add a New Attribute
- Follow the naming convention:
<Name>Attribute.cs+<Name>Tests.cs - Place in appropriate folder (
Network/,Text/,Classes/, etc.) - Use primary constructors where possible
- Write comprehensive tests (null, empty, valid, invalid, options, edge cases)
- Ensure all tests pass:
dotnet test
See Code Conventions & Guidelines for detailed style rules
📄 License
This project is licensed under the MIT License. See LICENSE for details
👥 Acknowledgments
Created and maintained by LuisAlfredo92 with the help of Lumo AI Assistant
Built with ❤️ for the .NET community
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.