Validation Attributes Reference
Complete reference for all validation attributes in Pragmatic.Validation.Attributes.
All attributes are in the namespace Pragmatic.Validation.Attributes. They target AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter unless noted otherwise.
General Rules
Section titled “General Rules”- Null values pass for all attributes except
[Required]. Use[Required]to enforce non-null, then combine with other attributes for format/range checks. - Types must be
partialfor the source generator to add theValidate()method (diagnosticPRAG0200). - Custom message keys — Every attribute has a
MessageKeyproperty to override the default localization key:[Email(MessageKey = "custom.invalid_email")]. - Multiple attributes — You can stack multiple attributes on the same property. They are all checked in order.
Presence Attributes
Section titled “Presence Attributes”[Required]
Section titled “[Required]”Validates that a value is not null. For strings, also validates not empty (unless AllowEmptyStrings = true).
| Property | Type | Default | Description |
|---|---|---|---|
AllowEmptyStrings | bool | false | When true, empty strings are accepted. |
MessageKey | string? | null | Custom localization key. |
Default message key: validation.required
Behavior by type:
string: null or empty string fails (unlessAllowEmptyStrings = true).- Reference types: null fails.
- Value types: always passes (they cannot be null).
requiredmodifier: The SG treats C#requiredproperties as having an implicit[Required]attribute.
[Required]public string Email { get; init; } = "";
[Required(AllowEmptyStrings = true)]public string Name { get; init; } = "";
[Required(MessageKey = "custom.email_required")]public string Email { get; init; } = "";[NotEmpty]
Section titled “[NotEmpty]”Validates that a string has length > 0, or a collection has count > 0.
Default message key: validation.notempty
Works with: string, Array, ICollection, IEnumerable.
[Required][NotEmpty]public List<OrderItem> Items { get; init; } = [];[NotWhiteSpace]
Section titled “[NotWhiteSpace]”Validates that a string is not null, empty, or whitespace only (spaces, tabs, newlines). Stricter than [Required] for strings — rejects " ".
Default message key: validation.notwhitespace
Non-string values always pass.
[NotWhiteSpace]public string Content { get; init; } = "";String Length Attributes
Section titled “String Length Attributes”[MinLength(length)]
Section titled “[MinLength(length)]”Validates minimum character count for strings, or minimum element count for collections/arrays.
| Constructor | Parameters |
|---|---|
MinLength(int length) | Minimum length/count (must be >= 0). |
Default message key: validation.minlength
[MinLength(2)]public string Name { get; init; } = "";
[MinLength(1)]public List<string> Tags { get; init; } = [];[MaxLength(length)]
Section titled “[MaxLength(length)]”Validates maximum character count for strings, or maximum element count for collections/arrays.
| Constructor | Parameters |
|---|---|
MaxLength(int length) | Maximum length/count (must be >= 0). |
Default message key: validation.maxlength
[MaxLength(100)]public string Name { get; init; } = "";
[MaxLength(10)]public List<string> Tags { get; init; } = [];[Length(minimumLength, maximumLength)]
Section titled “[Length(minimumLength, maximumLength)]”Combines [MinLength] and [MaxLength] into a single attribute. Validates that length/count is within the range (inclusive).
| Constructor | Parameters |
|---|---|
Length(int minimumLength, int maximumLength) | Both must be >= 0, minimum <= maximum. |
| Property | Type | Description |
|---|---|---|
MinimumLength | int | Minimum length/count. |
MaximumLength | int | Maximum length/count. |
Default message key: validation.length
[Length(2, 100)]public string Name { get; init; } = "";Format Attributes
Section titled “Format Attributes”[Email]
Section titled “[Email]”Validates that a string is a valid email address format. Uses a practical regex pattern (not strict RFC 5322). Maximum 254 characters (per RFC). Compiled with a 250ms regex timeout (ReDoS protection).
Has a static IsValidEmail(string?) method used by the SG for inline validation.
Default message key: validation.email
[Required][Email]public string Email { get; init; } = "";[Phone]
Section titled “[Phone]”Validates that a string is a valid phone number format. Accepts common formats including international (digits, spaces, hyphens, parentheses, optional leading +). Requires 7-15 digits.
Has a static IsValidPhone(string?) method.
Default message key: validation.phone
[Phone]public string? PhoneNumber { get; init; }// Valid: "+1 234 567-8900", "(234) 567-8900", "+39 02 1234567"Validates that a string is a valid URL.
| Property | Type | Default | Description |
|---|---|---|---|
AllowedSchemes | string[]? | ["http", "https"] | Allowed URI schemes. |
RequireAbsolute | bool | true | Whether to require absolute URIs. |
Has a static IsValidUrl(string?, string[]?, bool) method.
Default message key: validation.url
[Url]public string? Website { get; init; }
[Url(AllowedSchemes = new[] { "http", "https", "ftp" })]public string? FileUrl { get; init; }
[Url(RequireAbsolute = false)]public string? RelativeLink { get; init; }[CreditCard]
Section titled “[CreditCard]”Validates that a string is a valid credit card number using the Luhn algorithm (ISO/IEC 7812-1). Accepts 13-19 digits. Spaces and hyphens are stripped before validation.
Has a static IsValidCreditCard(string?) method.
Default message key: validation.creditcard
[Required][CreditCard]public string CardNumber { get; init; } = "";[Regex(pattern)]
Section titled “[Regex(pattern)]”Validates that a string matches a regular expression pattern. The regex is compiled with RegexOptions.Compiled | RegexOptions.CultureInvariant and a 250ms timeout.
Supports AllowMultiple = true — you can apply multiple [Regex] attributes to the same property.
| Constructor | Parameters |
|---|---|
Regex(string pattern) | The regex pattern (must not be null or empty). |
| Property | Type | Description |
|---|---|---|
Pattern | string | The regex pattern. |
Default message key: validation.regex
[Regex(@"^[A-Z]{2}-\d{4}$")]public string ProductCode { get; init; } = "";
[Regex(@"^\d{5}(-\d{4})?$", MessageKey = "validation.zipcode")]public string ZipCode { get; init; } = "";[Guid]
Section titled “[Guid]”Validates that a string is a valid GUID format. Accepts standard formats: D (with hyphens), N (digits only), B (braces), P (parentheses).
Has a static IsValidGuid(string?) method.
Default message key: validation.guid
[Required][Guid]public string ExternalId { get; init; } = "";Numeric Attributes
Section titled “Numeric Attributes”All numeric attributes support: int, long, short, byte, sbyte, uint, ulong, ushort, float, double, decimal.
[Range(minimum, maximum)]
Section titled “[Range(minimum, maximum)]”Validates that a numeric value is within a specified range (inclusive on both ends).
| Constructor | Parameters |
|---|---|
Range(int minimum, int maximum) | Integer bounds. |
Range(double minimum, double maximum) | Double bounds. |
| Property | Type | Description |
|---|---|---|
Minimum | object | Minimum value (inclusive). |
Maximum | object | Maximum value (inclusive). |
Default message key: validation.range
[Range(0, 100)]public decimal Price { get; init; }
[Range(1, 1000)]public int Quantity { get; init; }
[Range(0.0, 1.0)]public double Percentage { get; init; }[Positive]
Section titled “[Positive]”Validates that a numeric value is greater than zero. Zero is NOT considered positive.
Default message key: validation.positive
[Required][Positive]public decimal Amount { get; init; }[Negative]
Section titled “[Negative]”Validates that a numeric value is less than zero. Zero is NOT considered negative. Unsigned types always pass (they cannot be negative).
Default message key: validation.negative
[Negative]public decimal Adjustment { get; init; }[GreaterThan(value)]
Section titled “[GreaterThan(value)]”Validates that a numeric value is strictly greater than the specified value.
| Constructor | Parameters |
|---|---|
GreaterThan(int value) | Integer bound. |
GreaterThan(double value) | Double bound. |
Default message key: validation.greaterthan
[GreaterThan(0)]public decimal DiscountPercent { get; init; }[GreaterThanOrEqual(value)]
Section titled “[GreaterThanOrEqual(value)]”Validates that a numeric value is greater than or equal to the specified value.
| Constructor | Parameters |
|---|---|
GreaterThanOrEqual(int value) | Integer bound. |
GreaterThanOrEqual(double value) | Double bound. |
Default message key: validation.greaterthanorequal
[GreaterThanOrEqual(1)]public int Quantity { get; init; }[LessThan(value)]
Section titled “[LessThan(value)]”Validates that a numeric value is strictly less than the specified value.
| Constructor | Parameters |
|---|---|
LessThan(int value) | Integer bound. |
LessThan(double value) | Double bound. |
Default message key: validation.lessthan
[LessThan(150)]public int Age { get; init; }[LessThanOrEqual(value)]
Section titled “[LessThanOrEqual(value)]”Validates that a numeric value is less than or equal to the specified value.
| Constructor | Parameters |
|---|---|
LessThanOrEqual(int value) | Integer bound. |
LessThanOrEqual(double value) | Double bound. |
Default message key: validation.lessthanorequal
[LessThanOrEqual(100)]public decimal DiscountPercent { get; init; }Collection Attributes
Section titled “Collection Attributes”[MinCount(count)]
Section titled “[MinCount(count)]”Validates that a collection has at least the specified number of elements.
| Constructor | Parameters |
|---|---|
MinCount(int count) | Minimum element count (must be >= 0). |
Works with: Array, ICollection, IEnumerable.
Default message key: validation.mincount
[Required][MinCount(1)]public List<OrderItem> Items { get; init; } = [];[MaxCount(count)]
Section titled “[MaxCount(count)]”Validates that a collection does not exceed the specified number of elements.
| Constructor | Parameters |
|---|---|
MaxCount(int count) | Maximum element count (must be >= 0). |
Default message key: validation.maxcount
[MaxCount(10)]public List<string> Tags { get; init; } = [];[Count(minimumCount, maximumCount)]
Section titled “[Count(minimumCount, maximumCount)]”Combines [MinCount] and [MaxCount] into a single attribute.
| Constructor | Parameters |
|---|---|
Count(int minimumCount, int maximumCount) | Both must be >= 0, min <= max. |
| Property | Type | Description |
|---|---|---|
MinimumCount | int | Minimum element count. |
MaximumCount | int | Maximum element count. |
Default message key: validation.count
[Required][Count(2, 10)]public List<Guid> TeamMembers { get; init; } = [];[ValidateElements]
Section titled “[ValidateElements]”Indicates that each element in a collection should be validated individually. The element type must implement ISyncValidator (it must be a partial type with validation attributes).
This is NOT a ValidationAttribute — it is a standalone Attribute. The SG generates a loop that calls Validate() on each element. Error paths include the index: Items[0].ProductId.
| Property | Type | Default | Description |
|---|---|---|---|
StopOnFirstError | bool | false | Stop at the first invalid element. |
Diagnostics:
PRAG0204(Warning): Applied to a non-collection type.PRAG0205(Error): Element type does not implementISyncValidator.
public partial class OrderItemRequest{ [Required] public Guid ProductId { get; init; }
[Range(1, 100)] public int Quantity { get; init; }}
public partial class PlaceOrderRequest{ [Required] [NotEmpty] [ValidateElements] public List<OrderItemRequest> Items { get; init; } = [];}// Error path: "Items[0].ProductId", "Items[2].Quantity"Comparison Attributes (Cross-Property)
Section titled “Comparison Attributes (Cross-Property)”These attributes compare the decorated property against another property on the same type. They set RequiresInstance = true and use the IsValid(object?, object) overload.
At runtime, PropertyAccessorCache uses compiled expression tree delegates to access the other property’s value — no per-call reflection.
Diagnostic PRAG0203: Emitted as an error when the referenced property does not exist on the type.
Diagnostic PRAG0209: Emitted as a warning when the two properties have incompatible types.
[EqualTo(otherPropertyName)]
Section titled “[EqualTo(otherPropertyName)]”Validates that the property value equals another property’s value. Uses object.Equals(). Both null values are considered equal.
Default message key: validation.equalto
public partial class ChangePasswordRequest{ [Required] public string NewPassword { get; init; } = "";
[Required] [EqualTo(nameof(NewPassword))] public string ConfirmPassword { get; init; } = "";}[NotEqualTo(otherPropertyName)]
Section titled “[NotEqualTo(otherPropertyName)]”Validates that the property value does NOT equal another property’s value. If either value is null, the comparison passes.
Default message key: validation.notequalto
public partial class ChangePasswordRequest{ [Required] public string CurrentPassword { get; init; } = "";
[Required] [NotEqualTo(nameof(CurrentPassword))] public string NewPassword { get; init; } = "";}[GreaterThanProperty(otherPropertyName)]
Section titled “[GreaterThanProperty(otherPropertyName)]”Validates that the property value is greater than another property’s value. Both values must implement IComparable. Works with DateTime, DateTimeOffset, and numeric types.
Default message key: validation.greaterthanproperty
public partial class DateRangeRequest{ [Required] public DateTime StartDate { get; init; }
[Required] [GreaterThanProperty(nameof(StartDate))] public DateTime EndDate { get; init; }}[LessThanProperty(otherPropertyName)]
Section titled “[LessThanProperty(otherPropertyName)]”Validates that the property value is less than another property’s value.
Default message key: validation.lessthanproperty
public partial class PriceRangeRequest{ [Required] [LessThanProperty(nameof(MaxPrice))] public decimal MinPrice { get; init; }
[Required] public decimal MaxPrice { get; init; }}Conditional Attributes
Section titled “Conditional Attributes”[RequiredIf(otherPropertyName, expectedValue)]
Section titled “[RequiredIf(otherPropertyName, expectedValue)]”Makes a property conditionally required when another property equals the expected value.
Supports AllowMultiple = true — multiple [RequiredIf] attributes on the same property.
| Constructor | Parameters |
|---|---|
RequiredIf(string otherPropertyName, object? expectedValue) | Property name and trigger value. |
| Property | Type | Default | Description |
|---|---|---|---|
OtherPropertyName | string | — | Property to check. |
ExpectedValue | object? | — | Value that triggers the requirement. |
AllowEmptyStrings | bool | false | Whether empty strings are valid when required. |
Default message key: validation.requiredif
public partial class PaymentRequest{ [Required] public PaymentMethod Method { get; init; }
[RequiredIf(nameof(Method), PaymentMethod.CreditCard)] public string? CardNumber { get; init; }
[RequiredIf(nameof(Method), PaymentMethod.BankTransfer)] public string? BankAccount { get; init; }}[RequiredIfNot(otherPropertyName, excludedValue)]
Section titled “[RequiredIfNot(otherPropertyName, excludedValue)]”Makes a property conditionally required when another property does NOT equal the specified value.
Supports AllowMultiple = true.
| Constructor | Parameters |
|---|---|
RequiredIfNot(string otherPropertyName, object? excludedValue) | Property name and excluded value. |
| Property | Type | Default | Description |
|---|---|---|---|
OtherPropertyName | string | — | Property to check. |
ExcludedValue | object? | — | Value that, when NOT present, triggers the requirement. |
AllowEmptyStrings | bool | false | Whether empty strings are valid when required. |
Default message key: validation.requiredifnot
public partial class ContactRequest{ public string? Email { get; init; }
// Phone is required when Email is NOT null (i.e., user provided email) [RequiredIfNot(nameof(Email), null)] public string? Phone { get; init; }}
// Or: require Phone when ContactMethod is NOT Emailpublic partial class ContactRequest2{ [Required] public ContactMethod Method { get; init; }
[RequiredIfNot(nameof(Method), ContactMethod.Email)] public string? Phone { get; init; }}Extended / Type-Specific Attributes
Section titled “Extended / Type-Specific Attributes”[ValidEnum]
Section titled “[ValidEnum]”Validates that a value is a defined member of an enum type. Prevents invalid values assigned through casting (e.g., (Status)999).
Has a static generic IsValidEnum<TEnum>(TEnum value) method.
Default message key: validation.enum
[Required][ValidEnum]public OrderStatus Status { get; init; }[OneOf(allowedValues)]
Section titled “[OneOf(allowedValues)]”Validates that a value is one of a fixed set of allowed values. Uses object.Equals() for comparison.
| Constructor | Parameters |
|---|---|
OneOf(params object[] allowedValues) | The set of allowed values. |
| Property | Type | Description |
|---|---|---|
AllowedValues | object[] | The allowed values. |
Default message key: validation.oneof
[Required][OneOf("draft", "published", "archived")]public string Status { get; init; } = "";[FutureDate]
Section titled “[FutureDate]”Validates that a DateTime or DateTimeOffset is in the future. Compares against DateTime.UtcNow / DateTimeOffset.UtcNow.
Default message key: validation.future_date
Note: Uses DateTime.UtcNow directly because ValidationAttribute.IsValid() does not support dependency injection. The generated code has the same limitation.
[Required][FutureDate]public DateTimeOffset StartDate { get; init; }[PastDate]
Section titled “[PastDate]”Validates that a DateTime or DateTimeOffset is in the past.
Default message key: validation.past_date
Same DateTime.UtcNow limitation as [FutureDate].
[Required][PastDate]public DateTime BirthDate { get; init; }Special Attributes
Section titled “Special Attributes”[Validator]
Section titled “[Validator]”Marks a class as an async validator for DI auto-registration. Targets AttributeTargets.Class only.
| Property | Type | Default | Description |
|---|---|---|---|
Lifetime | ServiceLifetime | Scoped | DI service lifetime. |
The class must implement IAsyncValidator<T>. If it does not, diagnostic PRAG0201 is emitted.
[Validator]public class CreateUserValidator : IAsyncValidator<CreateUserRequest> { ... }
[Validator(Lifetime = ServiceLifetime.Transient)]public class ExpensiveValidator : IAsyncValidator<ComplexRequest> { ... }[AsyncValidate<TValidator>]
Section titled “[AsyncValidate<TValidator>]”Binds an async validator to a property or entity for change-aware invocation. Targets AttributeTargets.Property | AttributeTargets.Class. Supports AllowMultiple = true.
When applied to a property: the validator fires only when that property is modified. When applied to a class: the validator fires on any entity modification.
The SG generates IAsyncValidatorBindings<T> from these bindings.
// Property-level bindingpublic partial class User{ [AsyncValidate<EmailUniquenessValidator>] public string Email { get; private set; }}
// Entity-level binding[AsyncValidate<UserConsistencyValidator>]public partial class User { ... }Summary Table
Section titled “Summary Table”| Category | Attribute | Parameters | Default Message Key |
|---|---|---|---|
| Presence | [Required] | AllowEmptyStrings | validation.required |
[NotEmpty] | — | validation.notempty | |
[NotWhiteSpace] | — | validation.notwhitespace | |
| String | [MinLength(n)] | int length | validation.minlength |
[MaxLength(n)] | int length | validation.maxlength | |
[Length(min, max)] | int min, int max | validation.length | |
| Format | [Email] | — | validation.email |
[Phone] | — | validation.phone | |
[Url] | AllowedSchemes, RequireAbsolute | validation.url | |
[CreditCard] | — | validation.creditcard | |
[Regex(pattern)] | string pattern | validation.regex | |
[Guid] | — | validation.guid | |
| Numeric | [Range(min, max)] | int/double min, max | validation.range |
[Positive] | — | validation.positive | |
[Negative] | — | validation.negative | |
[GreaterThan(n)] | int/double value | validation.greaterthan | |
[GreaterThanOrEqual(n)] | int/double value | validation.greaterthanorequal | |
[LessThan(n)] | int/double value | validation.lessthan | |
[LessThanOrEqual(n)] | int/double value | validation.lessthanorequal | |
| Collection | [MinCount(n)] | int count | validation.mincount |
[MaxCount(n)] | int count | validation.maxcount | |
[Count(min, max)] | int min, int max | validation.count | |
[ValidateElements] | StopOnFirstError | N/A | |
| Comparison | [EqualTo(prop)] | string otherPropertyName | validation.equalto |
[NotEqualTo(prop)] | string otherPropertyName | validation.notequalto | |
[GreaterThanProperty(prop)] | string otherPropertyName | validation.greaterthanproperty | |
[LessThanProperty(prop)] | string otherPropertyName | validation.lessthanproperty | |
| Conditional | [RequiredIf(prop, value)] | string prop, object? value | validation.requiredif |
[RequiredIfNot(prop, value)] | string prop, object? value | validation.requiredifnot | |
| Extended | [ValidEnum] | — | validation.enum |
[OneOf(values)] | params object[] values | validation.oneof | |
[FutureDate] | — | validation.future_date | |
[PastDate] | — | validation.past_date | |
| DI | [Validator] | Lifetime | N/A |
| Binding | [AsyncValidate<T>] | — | N/A |