Nedo.AspNet.Request.Validation 1.2.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.2.2
                    
NuGet\Install-Package Nedo.AspNet.Request.Validation -Version 1.2.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.2.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.2.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.2.2
                    
#r "nuget: Nedo.AspNet.Request.Validation, 1.2.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.2.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.2.2
                    
Install as a Cake Addin
#tool nuget:?package=Nedo.AspNet.Request.Validation&version=1.2.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

📖 For detailed usage examples, parameters, and error codes for each validator, see the Validator Documentation.

Generic Validators

Attribute Description
[Required] Field must not be null or empty
[MinLength(n)] Minimum string/collection length
[MaxLength(n)] Maximum string/collection length
[ExactLength(n)] Length must match exactly
[LengthRange(min, max)] Length must be within range
[Regex("pattern")] Must match the specified regex pattern
[AllowedValues("a", "b", ...)] Value must be one of the listed values
[NotAllowedValues("a", "b")] Value must not be one of the listed values
[Equal("value")] Must equal the specified value
[NotEqual("value")] Must not equal the specified value
[ConditionalRequired] Required only when a condition is met
[ConditionalRequiredIfInList] Required when another property's value is in a list
[DynamicAllowedValues("key")] Allowed values from DI, keyed (IAllowedValuesProvider)
[DynamicNotAllowedValues("key")] Forbidden values from DI, keyed (INotAllowedValuesProvider)
[DynamicConditionalRequired("key")] Condition from DI, keyed (IConditionalRequiredProvider)
[Unique] Must be unique (DI required: Func<string, bool>)
[UniqueInList] All items in the list must be unique

Data Type Validators

Attribute Description
[IsBoolean] Must be a valid boolean value
[IsInteger] Must be a valid integer
[IsNumeric] Must be a valid numeric value
[IsDate] Must be a valid date
[IsDateTime] Must be a valid DateTime
[IsTime] Must be a valid time
[IsGuid] Must be a valid GUID

String Validators

Attribute Description
[Alpha] Letters only
[AlphaNumeric] Letters and numbers only
[AlphaSpaceQuote] Letters, spaces, and quotes only
[CamelCaseOnly] Must follow camelCase format
[PascalCaseOnly] Must follow PascalCase format
[SnakeCaseOnly] Must follow snake_case format
[KebabCaseOnly] Must follow kebab-case format
[TitleCaseOnly] Must follow Title Case format
[LowerCaseOnly] Lowercase letters only
[UpperCaseOnly] Uppercase letters only
[NumberOnlyString] Digits only
[NoWhitespace] No whitespace allowed
[NoSpecialCharacter] Special characters are not allowed
[Contains("value")] Must contain the specified value
[NotContains("value")] Must NOT contain the specified value
[StartsWith("value")] Must start with the specified value
[EndsWith("value")] Must end with the specified value
[CreditCard] Must be a valid credit card number
[JsonString] Must be a valid JSON string
[HexColor] Must be a valid hex color code
[SemVer] Must follow semantic versioning
[Slug] Must be a valid URL slug
[IPAddressString] Must be a valid IP address string
[MacAddress] Must be a valid MAC address
[Latitude] Must be a valid latitude value
[Longitude] Must be a valid longitude value

Numeric Validators

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

Email Validators

Attribute Description
[Email] Must be a valid email address
[DisposableEmail] Must not be a disposable email address
[EmailDomain("example.com")] Must match the specified email domain
[EmailProvider("gmail.com")] Must match the specified email provider

Password Validators

Attribute Description
[MinDigit(n)] Minimum number of digit characters
[MinLowerCase(n)] Minimum number of lowercase characters
[MinUpperCase(n)] Minimum number of uppercase characters
[MinSpecialChar(n)] Minimum number of special characters
[NoRepeatingChars(n)] No more than n consecutive repeating chars
[NotCommonPassword] Must not be a commonly used password

Date (DateOnly) Validators

Attribute Description
[ExactDate] Must match exact date
[DateRange(min, max)] Date must be within range
[DateFormat("fmt")] Must match the specified date format
[MinDate(date)] Minimum allowed date
[MaxDate(date)] Maximum allowed date
[PastDate] Must be in the past
[FutureDate] Must be in the future
[LeapYear] Must be in a leap year
[Weekday] Must be a weekday
[Weekend] Must be a weekend
[MinAge(n)] Minimum age in years
[MaxAge(n)] Maximum age in years
[CustomHoliday] Must not fall on a custom holiday (DI required)

DateTime / Time Validators

Attribute Description
[DateTimeRange] DateTime must be within range
[MinDateTime] Minimum DateTime
[MaxDateTime] Maximum DateTime
[PastDateTime] Must be in the past
[FutureDateTime] Must be in the future
[LeapYearDateTime] Must be in leap year
[WeekdayDateTime] Must be weekday
[WeekendDateTime] Must be weekend
[TimeRange] Time must be within range
[TimeOnlyRange] TimeOnly within range
[MinTime] Minimum time
[MaxTime] Maximum time
[AMOnly] Morning time only
[PMOnly] Afternoon/evening only

File Validators

Attribute Description
[FileType] Validate file extension
[FileMimeType] Validate MIME type
[FileMaxSize] Maximum file size
[FileMinSize] Minimum file size
[FileNameLength] Maximum filename length
[FileNamePattern] Filename regex validation
[FileNullBytes] Detect null bytes (file corruption)

Image Validators

Attribute Description
[ImageType] Allowed image types
[ImageFileNamePattern] Validate image filename
[MaxImageSize] Maximum image file size
[MinImageSize] Minimum image file size
[ImageResolution] Exact image resolution
[ExactDimension] Exact width and height
[MaxResolution] Maximum resolution
[MinResolution] Minimum resolution
[AspectRatio] Validate image aspect ratio
[PortraitImage] Height > width
[LandscapeImage] Width > height
[SquareImage] Width equals height
[ImageMagicBytes] Validate image file signature

IP Address Validators

Attribute Description
[IPv4Address] IPv4 format validation
[IPv6Address] IPv6 format validation
[MixedIPv4IPv6] IPv4 or IPv6
[PrivateIPAddress] Private IP range
[PublicIPAddress] Public IP only
[LoopbackIPAddress] Loopback address
[MulticastIPAddress] Multicast address
[BroadcastIPAddress] Broadcast address
[AnycastIPAddress] Anycast address
[ReservedIPAddress] Reserved IP
[GatewayIPAddress] Gateway address
[UnicastIPAddress] Unicast address
[StaticIPAddress] Static IP
[DynamicIPAddress] Dynamic IP
[ASNIPAddress] ASN validation
[ISPOrganizationIPAddress] ISP organization check
[CountryIPAddress] Country-based IP
[BlacklistedIPAddress] Blocklisted IP
[WhitelistedIPAddress] Allowlisted IP
[IPAddressInRange] IP range validation
[ValidCIDRNotation] CIDR notation validation
[ValidSubnetMask] Subnet mask validation
[ValidTTLForIPAddress] TTL validation
[ReverseDNSValidation] Reverse DNS lookup

Phone Validators

Attribute Description
[ValidPhoneFormat] Valid phone number format
[PhoneCountryCode("code")] Country code validation
[ValidPhoneCountryCode] Valid country code
[PhoneAllowedCountryCode(codes)] Restrict to allowed codes
[PhoneLength(min, max)] Phone number length validation

Money Validators

Attribute Description
[CurrencyFormat] Currency formatting
[ValidCurrencyCode] ISO currency code
[MinAmountMoney] Minimum amount
[MaxAmountMoney] Maximum amount
[PositiveAmountMoney] Must be positive
[NonZeroAmountMoney] Must not be zero
[MoneyDecimalPlaces] Decimal precision

URL Validators

Attribute Description
[ValidUrlFormat] URL format validation
[SecureUrl] HTTPS only
[AccessibleUrl] URL accessibility
[IPBasedUrl] IP-based URL
[DomainSpecificUrl] Domain restriction
[NoFragmentUrl] Disallow URL fragment
[PortCheckUrl] Validate port
[UrlPath] Path validation
[UrlQueryParameter] Query parameter validation

UUID Validators

Attribute Description
[Uuid] Valid UUID
[UuidV7] 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-013 Required, MaxLength, AllowedValues
DataType VAL-DTY-001 to VAL-DTY-007 IsBoolean, IsInteger, IsGuid
String VAL-STR-001 to VAL-STR-027 LowerCase, CreditCard, MacAddress
Numeric VAL-NUM-001 to VAL-NUM-011 MinValue, MaxValue, OddNumber
Email VAL-EML-001 to VAL-EML-004 Email, DisposableEmail, EmailDomain
Password VAL-PWD-001 to VAL-PWD-006 MinDigit, MinUpperCase, NotCommon
Date VAL-DAT-001 to VAL-DAT-013 DateRange, PastDate, MinAge
DateTime VAL-DTM-001 to VAL-DTM-014 DateTimeRange, MinTime, AMOnly
Phone VAL-PHN-001 to VAL-PHN-005 ValidPhoneFormat, PhoneLength
File VAL-FIL-001 to VAL-FIL-007 FileType, MaxFileSize, FileNullBytes
Image VAL-IMA-001 to VAL-IMA-013 ImageType, MaxResolution, Landscape
IP Address VAL-IPA-001 to VAL-IPA-024 IPv4, IPv6, PrivateIP
URL VAL-URL-001 to VAL-URL-009 ValidURL, SecureURL
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 -a v1.7.2 -m "Release v1.7.2

Added:
- README included in NuGet package for better package description
- Documentation: guide for pushing package to NuGet

Changed:
- Packaging configuration to embed README file

Notes:
No breaking changes. Existing consumers are not affected."


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

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