New Data Annotations in .NET 8 Web API

By: Syed Mohamed | Published on: September 10, 2025

Category: .Net Core

New Data Annotations in .NET 8 Web API

New and Enhanced Data Annotation Attributes in .NET 8

Here’s a clear breakdown of the new Data Annotation attributes introduced in .NET 8 for Web API (System.ComponentModel.DataAnnotations), along with enhancements to existing ones:

1. RequiredAttribute with DisallowAllDefaultValues

  • What it does: Ensures a value isn’t left at its default (e.g., Guid.Empty for Guid structs).

  • Use case: When using value types (structs) like Guid, simply marking them [Required] doesn't catch Guid.Empty. Now you can write:

  • [Required(DisallowAllDefaultValues = true)]
    public Guid MyId { get; set; }

This forces a non-default value.

RangeAttribute with MinimumIsExclusive and MaximumIsExclusive

  • What it does: Allows specifying whether range boundaries are inclusive or exclusive.

  • Example (both boundaries exclusive):

[Range(0, 100, MinimumIsExclusive = true, MaximumIsExclusive = true)]
public int Age { get; set; }

This restricts Age to values strictly between 0 and 100 (i.e., 1–99).

LengthAttribute

  • What it does: Validates minimum and maximum length for strings and collections.

Example:

[Length(5, 100)]
public string Username { get; set; }

[Length(1, 5)]
public List<string> Courses { get; set; }

This ensures proper sizing, improving input validation.

Base64StringAttribute

What it does: Validates that a string is valid Base64 format.

[Base64String]
public string Hash { get; set; }

Handy for validating encoded data—not intended for password storage.

AllowedValuesAttribute & DeniedValuesAttribute

AllowedValues: Specifies a list of permitted values.

[AllowedValues("Standard", "Premium", "Enterprise")]
public string Tier { get; set; }

DeniedValues: Specifies a list of prohibited values.

[DeniedValues("Admin", "Administrator")]
public string Username { get; set; }

These eliminate the need for custom validation logic for common scenarios.

Improved Performance via Source Generators for Options

When using these annotations on configuration classes (e.g., via IOptions<T>), validation is applied at startup using generated code—this results in faster startup and more efficient validation.

Summary Table

Attribute Purpose
Required(DisallowAllDefaultValues = true) Prevents default values (e.g., Guid.Empty)
Range(..., MinimumIsExclusive/MaximumIsExclusive) Exclusive/inclusive numeric range validation
Length(min, max) Enforces length on strings or collections
Base64String Validates Base64-encoded string
AllowedValues(...) Restricts value to specified list
DeniedValues(...) Prohibits specific values

public class ConfigOptions
{
    [Required(DisallowAllDefaultValues = true)]
    public Guid InstanceId { get; set; }

    [Range(1, 10, MinimumIsExclusive = true, MaximumIsExclusive = true)]
    public int RetryCount { get; set; }

    [Length(5, 50)]
    public string ApplicationName { get; set; }

    [Base64String]
    public string SigningKey { get; set; }

    [AllowedValues("Debug", "Release")]
    public string BuildMode { get; set; }

    [DeniedValues("Test", "Mock")]
    public string Environment { get; set; }
}

In an ASP.NET Core setup, you could bind and validate it like this:

builder.Services
    .AddOptions<ConfigOptions>()
    .BindConfiguration("Config")
    .ValidateDataAnnotations()
    .ValidateOnStart();

This ensures your application fails fast if configuration is invalid.

Why This Matters

  • Expressive validation rules—More concise and declarative than writing custom logic.

  • Better cloud-native configuration validation—Especially useful when validating options loaded from settings files or environment variables.

  • Performance optimized—Source generators reduce runtime overhead.

  • Cleaner models—Annotations remain close to the data, making the intention clearer.

 


Comments

No comments yet. Be the first to comment!