Skip to content

Expo Models

SteffenBlake edited this page Sep 28, 2026 · 1 revision

Validation models

Mark a model with [Expo] and declare it partial to generate validation from its properties. Expo adds IExpoValidatable, TryValidate, and a static Metadata property.

Define rules on a model

// CourseRegistration.cs
[Expo]
public sealed partial class CourseRegistration
{
    [IsRequired("A student email is required.")]
    [StringMatchesEmail]
    public string? StudentEmail { get; init; }

    [IsRequired]
    [StringHasMinimumLength(2)]
    public string? CourseCode { get; init; }
}

Each attribute checks one condition. StudentEmail must be present and match the email rule. CourseCode must be present and contain at least two characters.

Expo validates declared instance properties. Static properties and indexers are ignored. Keep rules on the model that declares the properties; the generated method does not collect inherited properties. For a model nested inside another type, its containing types must also be partial.

Run validation

Creating or changing a model does not run validation. Call TryValidate at the point where your application accepts the data:

var registration = new CourseRegistration
{
    StudentEmail = "not-an-email",
    CourseCode = "B"
};

if (!registration.TryValidate(out var errors))
{
    foreach (var error in errors)
    {
        Console.WriteLine($"{error.Pointer}: {error.Detail}");
    }
}

TryValidate returns true when all rules pass and supplies an empty error collection. On failure, it returns false and reports all failed rules. The example reports both the email format and course code length failures.

Required and optional values

Most built-in format and length rules accept null. Add [IsRequired] when a missing value should fail. [IsRequired] checks for null; it does not reject an empty string or collection.

C# required controls object initialization at compile time. [IsRequired] is the Expo runtime rule. Use the validation attribute even when another part of your application also enforces presence.

Comparison rules use C#'s default comparers rather than a general null-skipping rule. Custom rules choose their own null behavior. See Value rules and Custom rules.

Use validation through a contract

Code accepting IExpoValidatable can validate any generated model:

IExpoValidatable input = registration;
bool valid = input.TryValidate(out var validationErrors);

The interface exposes instance validation and static model metadata. See Errors and metadata for consuming both.

For automatic validation of HTTP requests, use Expo validation in ASP.NET Core.

Clone this wiki locally