Comparison Rules
Comparison rules compare a field against another field, a conditional value, an allowed set, object keys, or the other values inside the same collection. They are useful for confirmations, consent fields, repeated values, and request fields that must agree with each other.
Accepted
Requires the field to contain an accepted value such as true, yes, on, or 1.
[Accepted]RuleFor(x => x.TermsAccepted)
.Accepted();AcceptedIf
Requires the field to contain an accepted value when another field equals one of the provided values. An absent field fails once the condition matches, the same way an unticked checkbox fails [Accepted].
[AcceptedIf(string field, params object?[] values)]
[AcceptedIf("NewsletterEnabled", true)]RuleFor(x => x.MarketingConsent)
.AcceptedIf(x => x.NewsletterEnabled, true);Declined
Requires the field to contain a declined value such as false, no, off, or 0.
[Declined]RuleFor(x => x.AgeRestricted)
.Declined();DeclinedIf
Requires the field to contain a declined value when another field equals one of the provided values. An absent field fails once the condition matches, the same way it does for [Declined].
[DeclinedIf(string field, params object?[] values)]
[DeclinedIf("AgeRestricted", true)]RuleFor(x => x.ParentalApprovalDeclined)
.DeclinedIf(x => x.AgeRestricted, true);SameAs
Requires the field value to match another request field.
[SameAs(string field)]
[SameAs("Email")]RuleFor(x => x.EmailConfirmation)
.SameAs(x => x.Email);Different
Requires the field value to be different from another request field.
[Different(string field)]
[Different("CurrentPassword")]RuleFor(x => x.NewPassword)
.Different(x => x.CurrentPassword);Confirmed
Requires the field to match a confirmation field. Without an explicit target, the validator uses the property name with Confirmation appended.
[Confirmed(string? field = null)]
[Confirmed]
[Confirmed("RepeatPassword")]RuleFor(x => x.Password)
.Confirmed(x => x.PasswordConfirmation);In
Requires the field value to be inside a set of allowed values.
[In(params object?[] values)]
[In("admin", "editor")]RuleFor(x => x.Role)
.In("admin", "editor");NotIn
Requires the field value to be outside a set of forbidden values.
[NotIn(params object?[] values)]
[NotIn("admin", "system")]RuleFor(x => x.Username)
.NotIn("admin", "system");InArray
Requires the field value to exist in another array-like request field.
[InArray(string field)]
[InArray("AllowedRoleIds")]RuleFor(x => x.RoleId)
.InArray(x => x.AllowedRoleIds);InArrayKeys
Requires an object or dictionary-like field to contain at least one of the provided keys.
[InArrayKeys(params string[] keys)]
[InArrayKeys("theme", "locale")]RuleFor(x => x.Settings)
.InArrayKeys("theme", "locale");RequiredArrayKeys
Requires an object or dictionary-like field to contain all provided keys.
[RequiredArrayKeys(params string[] keys)]
[RequiredArrayKeys("street", "city", "postalCode")]RuleFor(x => x.Address)
.RequiredArrayKeys("street", "city", "postalCode");Distinct
Requires all values in an array-like field to be unique.
[Distinct]RuleFor(x => x.RoleIds)
.Distinct();Regex
Requires the value to match the regular expression pattern.
The optional description is passed to the message template as {0}, so a failure can state the expected shape instead of only saying the value is invalid.
Each match runs under a timeout, one second by default, after which the match is abandoned and the rule fails. This bounds catastrophic backtracking on attacker-supplied input, which would otherwise pin a CPU core with no way to cancel it. Raise matchTimeoutSeconds only for a pattern that legitimately needs longer.
[Regex(string pattern, RegexOptions options = RegexOptions.None, string? description = null, double matchTimeoutSeconds = 1)]
[Regex("^[a-z0-9-]+$", RegexOptions.IgnoreCase, "lowercase letters, digits, and hyphens")]RuleFor(x => x.Slug)
.Regex("^[a-z0-9-]+$", RegexOptions.IgnoreCase, "lowercase letters, digits, and hyphens");NotRegex
Requires the value to not match the regular expression pattern.
Takes the same optional description and match timeout as Regex.
[NotRegex(string pattern, RegexOptions options = RegexOptions.None, string? description = null, double matchTimeoutSeconds = 1)]
[NotRegex("^admin-", RegexOptions.None, "must not start with admin-")]RuleFor(x => x.Username)
.NotRegex("^admin-", description: "must not start with admin-");