Nedo.AspNet.Request.Validation 1.1.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Nedo.AspNet.Request.Validation --version 1.1.2
                    
NuGet\Install-Package Nedo.AspNet.Request.Validation -Version 1.1.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nedo.AspNet.Request.Validation" Version="1.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nedo.AspNet.Request.Validation" Version="1.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Nedo.AspNet.Request.Validation" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nedo.AspNet.Request.Validation --version 1.1.2
                    
#r "nuget: Nedo.AspNet.Request.Validation, 1.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nedo.AspNet.Request.Validation@1.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nedo.AspNet.Request.Validation&version=1.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Nedo.AspNet.Request.Validation&version=1.1.2
                    
Install as a Cake Tool

Nedo.AspNet.Request.Validation

An annotation-based request validation library for ASP.NET Core, built to work with Nedo.AspNet.Common.Validation.Core.

This library allows you to validate HTTP request DTOs using attributes, while keeping validation logic centralized, reusable, and independent from controllers.


Features

  • Validate request DTOs using attributes
  • Produce consistent error codes & messages
  • Support multi-language validation messages
  • Integrate cleanly with ASP.NET Core + Swagger

Architecture

ASP.NET Core Application
    ↓
Custom Middleware (Culture / Policy)
    ↓
IRequestValidationContext
    ↓
Request.Validation (Attributes)
    ↓
Common.Validation.Core (Rules)
    ↓
Localization (.resx)

Important This library does not:

  • read HTTP headers automatically
  • decide culture
  • access database directly

Those are application responsibilities.


Installation

dotnet add package Nedo.AspNet.Request.Validation --version x.x.x

Use the latest version available on NuGet. Or via local NuGet if you are developing the library.


Program.cs Configuration (REQUIRED)

1. Register Request Validation

using Nedo.AspNet.Request.Validation.Extensions;

builder.Services.AddRequestValidation();

2. Disable ASP.NET Core implicit [Required] (IMPORTANT)

ASP.NET Core automatically treats non-nullable reference types as [Required]. This option disables that behavior so all validation is handled explicitly by Nedo.AspNet.Request.Validation.

builder.Services.AddControllers(options =>
{
    options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
});

Why this matters:

  • Prevents ASP.NET Core from auto-injecting [Required]
  • Ensures all validation flows through this library
  • Keeps error codes & messages consistent

Localization & Language Handling

Default behavior

Validation messages default to English (en).

This comes from the default implementation:

public sealed class RequestValidationContext : IRequestValidationContext
{
    public CultureInfo CurrentCulture { get; set; }

    public RequestValidationContext()
    {
        CurrentCulture = new CultureInfo("en");
    }
}

Not Automatic

The library does NOT automatically read Accept-Language.

Culture must be provided by the application.


✅ Custom Culture Middleware (Example)

using System.Globalization;
using Nedo.AspNet.Request.Validation.Abstractions;

public sealed class RequestCultureMiddleware
{
    private readonly RequestDelegate _next;

    public RequestCultureMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context, IRequestValidationContext validationContext)
    {
        CultureInfo? culture =
            TryGetFromHeader(context) ??
            TryGetFromJwt(context);

        if (culture is not null)
        {
            validationContext.CurrentCulture = culture;
            CultureInfo.CurrentCulture = culture;
            CultureInfo.CurrentUICulture = culture;
        }

        await _next(context);
    }

    private CultureInfo? TryGetFromHeader(HttpContext context)
    {
        var header = context.Request.Headers["Accept-Language"]
            .FirstOrDefault()?
            .Split(',')[0]
            .Split('-')[0]
            .Trim();

        return TryCreateCulture(header);
    }

    private CultureInfo? TryGetFromJwt(HttpContext context)
    {
        if (context.User.Identity?.IsAuthenticated != true)
            return null;

        return TryCreateCulture(context.User.FindFirst("language")?.Value);
    }

    private static CultureInfo? TryCreateCulture(string? cultureName)
    {
        if (string.IsNullOrWhiteSpace(cultureName))
            return null;

        try
        {
            return new CultureInfo(cultureName);
        }
        catch (CultureNotFoundException)
        {
            return null;
        }
    }
}

Register it:

app.UseMiddleware<RequestCultureMiddleware>();

Sample Application (Swagger Demo)

A runnable example is provided in:

samples/ConsoleDemo

▶️ How to Run

cd samples/ConsoleDemo
dotnet run

Then open your browser:

http://localhost:xxxx/swagger

To try different validation scenarios, modify the attributes in:

samples/ConsoleDemo/Models/ValidationTestRequest.cs


Sample Request Model

using Nedo.AspNet.Request.Validation.Attributes.Generic;
using Nedo.AspNet.Request.Validation.Attributes.String;

public class ValidationTestRequest
{
    [CamelCaseOnly]
    [MaxLength(25)]
    public string Name { get; set; } = string.Empty;

    [Required]
    [MaxLength(1)]
    public string Email { get; set; } = string.Empty;

    [MaxLength(50)]
    public string? Description { get; set; }
}

Example Invalid Request (via Swagger)

{
  "name": "JOHN_DOE",
  "email": ""
}

Example Validation Response

{
  "success": false,
  "code": "VAL-001",
  "message": "Validation failed",
  "error": [
    {
      "errorDetails": {
        "fieldErrors": [
          {
            "field": "Name",
            "code": "VAL-GEN-006",
            "message": "The string 'Name' must be in camelCase format."
          },
          {
            "field": "Email",
            "code": "VAL-GEN-001",
            "message": "The field 'Email' is required."
          }
        ]
      }
    }
  ]
}

Custom Validators (DI REQUIRED)

Some validators require runtime dependencies and must be registered manually using Dependency Injection.

🔹 CustomHoliday Validator

Signature (Common layer):

Func<int, int, bool>

Usage:

[CustomHoliday]
public DateOnly EventDate { get; set; }

🔹 Unique Validator

Signature (Common layer):

Func<string, bool>
YourApp/
├── Extensions/
│   └── ServiceCollectionExtensions.cs
├── Program.cs

Service Collection Extension

Extensions/ServiceCollectionExtensions.cs

using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;

namespace YourApp.Extensions;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddValidationDependencies(
        this IServiceCollection services)
    {
        // CustomHoliday validator dependency
        services.AddSingleton<Func<int, int, bool>>(_ =>
        {
            return (month, day) =>
                (month == 1 && day == 1) ||   // New Year
                (month == 12 && day == 25);   // Christmas
        });

        // Unique validator dependency
        services.AddScoped<Func<string, bool>>(provider =>
        {
            var db = provider.GetRequiredService<AppDbContext>();
            return value => db.Users.Any(u => u.Email == value);
        });

        return services;
    }
}

Notes:

  • Func<int, int, bool> → used by CustomHolidayValidator
  • Func<string, bool> → used by UniqueValidator
  • Business logic stays inside the application, not the library

Program.cs Registration

builder.Services.AddValidationDependencies();

Without this registration → the validator will not work.


Supported Validators

Generic Validators

Attribute Validator Description
[Required] RequiredValidator Field must not be null or empty
[MinLength(n)] MinLengthValidator Minimum string length
[MaxLength(n)] MaxLengthValidator Maximum string length
[ExactLength(n)] ExactLengthValidator String length must match exactly

String Validators

Attribute Validator Description
[Alpha] AlphaValidator Letters only
[AlphaNumeric] AlphaNumericValidator Letters and numbers only
[AlphaSpaceQuote] AlphaSpaceQuoteValidator Letters, spaces, and quotes only
[CamelCaseOnly] CamelCaseValidator Must follow camelCase format
[PascalCaseOnly] PascalCaseValidator Must follow PascalCase format
[SnakeCaseOnly] SnakeCaseValidator Must follow snake_case format
[KebabCaseOnly] KebabCaseValidator Must follow kebab-case format
[LowerCaseOnly] LowerCaseValidator Lowercase letters only
[UpperCaseOnly] UpperCaseValidator Uppercase letters only
[TitleCaseOnly] TitleCaseValidator Must follow Title Case format
[NumberOnlyString] NumberOnlyStringValidator Digits only
[NoWhitespace] NoWhitespaceValidator No whitespace allowed
[NoSpecialCharacter] NoSpecialCharacterValidator Special characters are not allowed
[Contains("value")] ContainsValidator Must contain the specified value
[NotContains("value")] NotContainsValidator Must NOT contain the specified value
[StartsWith("value")] StartsWithValidator Must start with the specified value
[EndsWith("value")] EndsWithValidator Must end with the specified value

Numeric Validators

Attribute Validator Description
[MinValue(n)] MinValueValidator Minimum numeric value
[MaxValue(n)] MaxValueValidator Maximum numeric value
[Range(min, max)] RangeValidator Value must be within range
[PositiveNumber] PositiveNumberValidator Must be greater than zero
[NegativeNumber] NegativeNumberValidator Must be less than zero
[NonZero] NonZeroValidator Value must not be zero
[EvenNumber] EvenNumberValidator Must be an even number
[OddNumber] OddNumberValidator Must be an odd number
[WholeNumber] WholeNumberValidator Must be a whole number
[DivisibleBy(n)] DivisibleByValidator Must be divisible by specified number
[DecimalPlaces(n)] DecimalPlacesValidator Limit decimal places

Date (DateOnly) Validators

Attribute Validator Description
[ExactDate] ExactDateValidator Must match exact date
[DateRange(min, max)] DateRangeValidator Date must be within range
[MinDate(date)] MinDateValidator Minimum allowed date
[MaxDate(date)] MaxDateValidator Maximum allowed date
[PastDate] PastDateValidator Must be in the past
[FutureDate] FutureDateValidator Must be in the future
[LeapYear] LeapYearValidator Must be in a leap year
[Weekday] WeekdayValidator Must be a weekday
[Weekend] WeekendValidator Must be a weekend
[CustomHoliday] CustomHolidayValidator Must not fall on a custom holiday (DI required)

DateTime / Time Validators

Attribute Validator Description
[DateTimeRange] DateTimeRangeValidator DateTime must be within range
[MinDateTime] MinDateTimeValidator Minimum DateTime
[MaxDateTime] MaxDateTimeValidator Maximum DateTime
[PastDateTime] PastDateTimeValidator Must be in the past
[FutureDateTime] FutureDateTimeValidator Must be in the future
[LeapYearDateTime] LeapYearDateTimeValidator Must be in leap year
[WeekdayDateTime] WeekdayDateTimeValidator Must be weekday
[WeekendDateTime] WeekendDateTimeValidator Must be weekend
[TimeRange] TimeRangeValidator Time must be within range
[TimeOnlyRange] TimeOnlyRangeValidator TimeOnly within range
[MinTime] MinTimeValidator Minimum time
[MaxTime] MaxTimeValidator Maximum time
[AMOnly] AMOnlyValidator Morning time only
[PMOnly] PMOnlyValidator Afternoon/evening only

File Validators

Attribute Validator Description
[FileType] FileTypeValidator Validate file extension
[FileMimeType] FileMimeTypeValidator Validate MIME type
[FileMaxSize] FileMaxSizeValidator Maximum file size
[FileMinSize] FileMinSizeValidator Minimum file size
[FileNameLength] FileNameLengthValidator Maximum filename length
[FileNamePattern] FileNamePatternValidator Filename regex validation
[FileNullBytes] FileNullBytesValidator Detect null bytes (file corruption)

Image Validators

Attribute Validator Description
[ImageType] ImageTypeValidator Allowed image types
[ImageMimeType] ImageMimeTypeValidator Validate image MIME type
[ImageFileNamePattern] ImageFileNamePatternValidator Validate image filename
[MaxImageSize] MaxImageSizeValidator Maximum image file size
[MinImageSize] MinImageSizeValidator Minimum image file size
[ImageResolution] ImageResolutionValidator Exact image resolution
[MaxResolution] MaxResolutionValidator Maximum resolution
[MinResolution] MinResolutionValidator Minimum resolution
[AspectRatio] AspectRatioValidator Validate image aspect ratio
[PortraitImage] PortraitImageValidator Height > width
[SquareImage] SquareImageValidator Width equals height
[ImageMagicBytes] ImageMagicBytesValidator Validate image file signature

IP Address Validators

Attribute Validator Description
[IPv4Address] IPv4Validator IPv4 format validation
[IPv6Address] IPv6Validator IPv6 format validation
[MixedIPv4IPv6] MixedIPValidator IPv4 or IPv6
[PrivateIPAddress] PrivateIPValidator Private IP range
[PublicIPAddress] PublicIPValidator Public IP only
[LoopbackIPAddress] LoopbackIPValidator Loopback address
[MulticastIPAddress] MulticastIPValidator Multicast address
[BroadcastIPAddress] BroadcastIPValidator Broadcast address
[AnycastIPAddress] AnycastIPValidator Anycast address
[ReservedIPAddress] ReservedIPValidator Reserved IP
[GatewayIPAddress] GatewayIPValidator Gateway address
[UnicastIPAddress] UnicastIPValidator Unicast address
[StaticIPAddress] StaticIPValidator Static IP
[DynamicIPAddress] DynamicIPValidator Dynamic IP
[ASNIPAddress] ASNIPValidator ASN validation
[ISPOrganizationIPAddress] ISPOrgIPValidator ISP organization check
[CountryIPAddress] CountryIPValidator Country-based IP
[BlacklistedIPAddress] BlacklistedIPValidator Blocklisted IP
[WhitelistedIPAddress] WhitelistedIPValidator Allowlisted IP
[IPAddressInRange] IPRangeValidator IP range validation
[ValidCIDRNotation] CIDRValidator CIDR notation validation
[ValidSubnetMask] SubnetMaskValidator Subnet mask validation
[ValidTTLForIPAddress] TTLValidator TTL validation
[ReverseDNSValidation] ReverseDNSValidator Reverse DNS lookup

Phone Validators

Attribute Validator Description
[ValidPhoneFormat] PhoneFormatValidator Valid phone number format
[PhoneCountryCode] PhoneCountryCodeValidator Country code validation
[ValidPhoneCountryCode] ValidPhoneCountryCodeValidator Valid country code

Money Validators

Attribute Validator Description
[CurrencyFormat] CurrencyFormatValidator Currency formatting
[ValidCurrencyCode] CurrencyCodeValidator ISO currency code
[MinAmountMoney] MinAmountMoneyValidator Minimum amount
[MaxAmountMoney] MaxAmountMoneyValidator Maximum amount
[PositiveAmountMoney] PositiveAmountValidator Must be positive
[NonZeroAmountMoney] NonZeroAmountValidator Must not be zero
[MoneyDecimalPlaces] MoneyDecimalPlacesValidator Decimal precision

URL Validators

Attribute Validator Description
[ValidUrlFormat] UrlFormatValidator URL format validation
[SecureUrl] SecureUrlValidator HTTPS only
[AccessibleUrl] AccessibleUrlValidator URL accessibility
[IPBasedUrl] IPBasedUrlValidator IP-based URL
[DomainSpecificUrl] DomainUrlValidator Domain restriction
[NoFragmentUrl] NoFragmentValidator Disallow URL fragment
[PortCheckUrl] PortCheckValidator Validate port
[UrlPath] UrlPathValidator Path validation
[UrlQueryParameter] UrlQueryValidator Query parameter validation

UUID Validators

Attribute Validator Description
[Uuid] UuidValidator Valid UUID
[UuidV7] UuidV7Validator UUID version 7

Error Codes Reference

All error codes are inherited from Common.Validation.Core:

Category Code Range Examples
Generic VAL-GEN-001 to VAL-GEN-006 Required, MaxLength, MinLength
String VAL-STR-001 to VAL-STR-017 LowerCase, UpperCase, AlphaNumeric
Numeric VAL-NUM-001 to VAL-NUM-011 MinValue, MaxValue, OddNumber
Date/Time VAL-DAT-001 to VAL-DTM-014 DateRange, MinTime, MaxDateTime
Phone VAL-PHN-001 to VAL-PHN-003 ValidPhoneFormat
File VAL-FIL-001 to VAL-FIL-006 FileType, MaxFileSize
Image VAL-IMA-001 to VAL-IMA-012 ImageType, MaxResolution
IP Address VAL-IPA-001 to VAL-IPA-026 IPv4, IPv6, PrivateIP
URL VAL-URL-001 to VAL-URL-009 ValidURL, SecureURL
Location VAL-LOC-001 to VAL-LOC-003 LatitudeRange, LongitudeRange
Money VAL-MON-001 to VAL-MON-007 MinAmount, CurrencyFormat

See Common.Validation README for complete list.


Dependencies

  • Nedo.AspNet.Common.Validation.Core (>= 1.0.0) - Core validation logic
  • Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0) - DI support
  • .NET 9.0 - Target framework

Project Structure

Nedo.AspNet.Request.Validation/
├── src/
│   └── Nedo.AspNet.Request.Validation/
│       ├── Abstractions/          # Core abstractions (interfaces)
│       ├── Attributes/            # Validation attributes
│       │   ├── Base/              # Base attribute classes
│       │   ├── Generic/           # Required, Length, Regex
│       │   ├── String/            # String format rules
│       │   ├── Numeric/           # Numeric validation
│       │   ├── Date/              # DateOnly validators
│       │   ├── DateTimeValidation/# DateTime & TimeOnly validators
│       │   ├── File/              # File upload validators
│       │   ├── Image/             # Image-specific validators
│       │   ├── IP/                # IP address validators
│       │   ├── Phone/             # Phone number validators
│       │   ├── Money/             # Currency & money validators
│       │   ├── URL/               # URL validators
│       │   └── Uuid/              # UUID validators
│       ├── Context/               # RequestValidationContext
│       ├── Extensions/            # DI & service extensions
│       ├── Filters/               # Validation filters
│       └── bin/                   # Build output
├── tests/
│   └── Nedo.AspNet.Request.Validation.Tests/
│       └── Attributes/            # Attribute unit tests
└── samples/
    └── ConsoleDemo/               # Runnable Swagger demo


Versioning & Release

This project uses git tags to control versioning. The GitLab CI/CD pipeline automatically builds and publishes NuGet packages when a tag is pushed.

How It Works

  1. The pipeline triggers only on tags (e.g. v1.1.1)
  2. The v prefix is stripped to get the version number (1.1.1)
  3. The package is built, packed, and published to NuGet.org

How to Release a New Version

# 1. Commit and push your changes
git add .
git commit -m "feat: your changes"
git push origin main

# 2. Create a version tag
git tag v1.1.1

# 3. Push the tag (this triggers the CI/CD pipeline)
git push origin v1.1.1

Version Format

Type Example Tag NuGet Version
Patch v1.0.1 1.0.1
Minor v1.1.0 1.1.0
Major v2.0.0 2.0.0
Prerelease v1.1.0-beta.1 1.1.0-beta.1

The tag must start with v (e.g. v1.1.1, not 1.1.1).


Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/YourFeature)
  3. Commit your changes (git commit -m "Add awesome feature")
  4. Push to your branch (git push origin feature/YourFeature)
  5. Open a pull request

Please ensure:

  • All tests pass (dotnet test)
  • Code follows project conventions
  • Add unit tests for new validators

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Nedo.AspNet.Request.Validation:

Package Downloads
Nedo.AspNet.ApiContracts

Standardized API request and response contracts for ASP.NET applications with snake_case JSON, structured validation errors, Swagger integration, and query engine support (filtering, sorting, pagination).

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.3 48 2/13/2026
1.2.2 66 2/12/2026
1.2.1 50 2/12/2026
1.2.0 53 2/12/2026
1.1.2 95 2/11/2026
1.1.1 49 2/11/2026
1.1.0 90 1/26/2026
1.0.0 89 1/18/2026