Class ValidationCodeProjection
- Namespace
- Trellis.FluentValidation
- Assembly
- Trellis.FluentValidation.dll
Maps a FluentValidation ErrorCode onto the Trellis reason-code vocabulary.
public static class ValidationCodeProjection
- Inheritance
-
ValidationCodeProjection
- Inherited Members
Remarks
FluentValidation defaults a failure's ErrorCode to the validator's type name —
"NotEmptyValidator", "GreaterThanValidator". Those names are stable and
well-known, but they are FluentValidation's vocabulary, not Trellis's: a client would have to
key on NotEmptyValidator from a FluentValidation rule and value.not-empty from a
generated TryCreate for the same condition. Translating here is what lets one client
branch cover both producers.
The table is keyed on the error-code string, never the CLR validator type. The two
disagree in practice: AspNetCoreCompatibleEmailValidator reports
Name = "EmailValidator", so a type-keyed lookup would miss it while a string-keyed one
hits. Keying on the string also means a caller's WithErrorCode("EmailValidator") maps
identically to the built-in rule, which is the behaviour a reader expects.
Four rules, in order:
- A blank code becomes the neutral sentinel — there is nothing to report.
- The legacy placeholder
validation.errorbecomes the sentinel, so an application that adopted the old placeholder is not mistaken for one making a deliberate statement. - A reserved name becomes its mapped Trellis code.
- Anything else passes through verbatim. A caller who wrote
WithErrorCode("order.too-large")means it, and silently rewriting it would makeWithErrorCodeuseless.
PredicateValidator and AsyncPredicateValidator map to the sentinel rather than to
a code of their own. A Must(...) rule can express any condition whatsoever, so its
validator name says only "some custom predicate failed" — which is precisely what the sentinel
means. Minting a predicate.failed code would look informative while telling a client
nothing it could branch on.
Methods
Project(string?)
Translates a FluentValidation error code into a Trellis reason code.
public static string Project(string? errorCode)
Parameters
Returns
- string
The mapped Trellis code for a reserved FluentValidation validator name, the neutral sentinel for a blank or legacy-placeholder code, and
errorCodeunchanged otherwise.
Project(string?, object?)
Translates a FluentValidation error code into a Trellis reason code, refining
NotEmptyValidator against the value that was actually rejected.
public static string Project(string? errorCode, object? attemptedValue)
Parameters
errorCodestringThe failure's
ErrorCode; may be null or blank.attemptedValueobjectThe failure's
AttemptedValue.
Returns
- string
The mapped Trellis code.
Remarks
FluentValidation's NotEmpty() is one rule covering three failures the vocabulary keeps
apart: an absent value is value.not-null, a present-but-blank string or empty
collection is value.not-empty, and a value type left at its default —
Guid.Empty, 0, default(DateTime) — is value.not-default. Mapping
the rule to a single code would make RuleFor(x => x.Id).NotEmpty() report
value.not-empty for Guid.Empty while a Trellis primitive reports
value.not-default for the same input, which is exactly the producer divergence the
vocabulary exists to remove. The code describes the failure, not the rule that caught it.