Common.NET-Validation-Framework 2.0.2

dotnet add package Common.NET-Validation-Framework --version 2.0.2
                    
NuGet\Install-Package Common.NET-Validation-Framework -Version 2.0.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="Common.NET-Validation-Framework" Version="2.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Common.NET-Validation-Framework" Version="2.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Common.NET-Validation-Framework" />
                    
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 Common.NET-Validation-Framework --version 2.0.2
                    
#r "nuget: Common.NET-Validation-Framework, 2.0.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 Common.NET-Validation-Framework@2.0.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=Common.NET-Validation-Framework&version=2.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Common.NET-Validation-Framework&version=2.0.2
                    
Install as a Cake Tool

C# Simple Validation Framework

.NET NuGet

A lightweight, flexible, and extensible validation framework for .NET applications. This framework provides a clean and intuitive way to validate various data types with customizable rules and detailed error reporting.

What's New in Version 2.0

  • โœจ Async Validation Support: New AsyncValidator<T> class with AddAsyncRule method for asynchronous validation
  • ๐Ÿ”„ New Validators: Added 50+ new built-in validators covering common scenarios:
    • Identifiers: GUID, UUID, SSN, CVV, Credit Card Expiry
    • Network: IP Address (IPv4/IPv6), Domain, URL, JWT, API Key
    • Files: File Extension, MIME Type
    • Versioning: Semantic Version
    • Codes: Currency Code, Language Code, Country Code, Postal Code
    • Location: Latitude, Longitude, Coordinates, Time Zone
    • Text: Letters Only (with Unicode support), Slug
    • Security: Strong Password (customizable requirements)
    • Colors: Color codes (Hex, RGB, RGBA, HSL, HSLA)
    • International: International Phone, Postal Codes by Country
  • ๐Ÿš€ Improved CI/CD: Updated GitHub Actions workflow to .NET 9.0 with automatic NuGet package generation
  • ๐Ÿ“ฆ Better Packaging: Enhanced NuGet package configuration with symbols and source link support
  • ๐Ÿงช More Tests: Comprehensive test coverage for all new features (100+ tests)

Table of Contents

Features

  • โœจ Fluent API for building validation rules
  • ๐ŸŽฏ Type-safe validation
  • ๐Ÿ“ Detailed error reporting
  • ๐Ÿ”ง Easily extensible
  • ๐Ÿ—๏ธ 70+ built-in validators for common scenarios
  • ๐Ÿ”„ Chainable validation rules
  • ๐Ÿ“Š Field-specific error tracking
  • โšก Async validation support with AsyncValidator<T>
  • ๐Ÿงฉ Full .NET Ecosystem Compatibility: ASP.NET Core, WPF, Windows Forms, Blazor, and .NET MAUI
  • ๐ŸŽจ Clean and maintainable code structure
  • ๐Ÿงช Comprehensive test coverage (120+ tests)
  • ๐Ÿ“ฆ NuGet package ready

Documentation

Comprehensive documentation is available for this framework:

๐Ÿ“š Online Documentation

๐Ÿ“– Documentation Generation

This project uses DocFX (Microsoft's documentation generator) for automatic documentation generation:

  • XML Documentation: Built-in .NET feature, generates IntelliSense docs
  • DocFX: Generates static documentation website
  • GitHub Actions: Automatically builds and deploys documentation
  • GitHub Pages: Hosts the live documentation site

To generate documentation locally:

# Install DocFX
dotnet tool install -g docfx

# Build project (generates XML docs)
dotnet build ValidationFramework/ValidationFramework.csproj -c Release

# Generate documentation
docfx docfx.json

# View locally
docfx docfx.json --serve

Documentation Structure:

๐Ÿ“ docs/
โ”œโ”€โ”€ index.md              # Home page
โ”œโ”€โ”€ toc.yml               # Table of contents
โ”œโ”€โ”€ docfx.json            # DocFX configuration
โ””โ”€โ”€ articles/             # Conceptual documentation
    โ”œโ”€โ”€ overview.md
    โ”œโ”€โ”€ installation.md
    โ”œโ”€โ”€ quick-start.md
    โ””โ”€โ”€ ...

See DOCS.md for detailed documentation setup information.


Installation

  1. Clone the repository or copy the ValidationFramework namespace files into your project.
  2. Add the following using statement to your code:
using ValidationFramework;

NuGet Package

Install via NuGet Package Manager:

Install-Package Common.NET-Validation-Framework

Or via .NET CLI:

dotnet add package Common.NET-Validation-Framework

Source Code

Alternatively, include the source files directly in your project:

  1. Copy all files from ValidationFramework/ directory
  2. Add to your project
  3. Ensure ValidationFramework.csproj settings are applied

Quick Start

Here's a simple example to get you started:

// Create a validator for an email field
var emailValidator = CommonValidators.EmailValidator();

// Validate an email
var result = emailValidator.Validate("john.doe@example.com");

if (result.IsValid)
{
    Console.WriteLine("Email is valid!");
}
else
{
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error: {error}");
    }
}

Usage Examples

Basic Field Validation

// Email validation
var emailValidator = CommonValidators.EmailValidator();
var emailResult = emailValidator.Validate("john.doe@example.com");

// Name validation
var nameValidator = CommonValidators.NameValidator(minLength: 2, maxLength: 50);
var nameResult = nameValidator.Validate("John");

// Phone validation
var phoneValidator = CommonValidators.PhoneValidator(requiredLength: 10);
var phoneResult = phoneValidator.Validate("1234567890");

WinForms (ErrorProvider)

var result = validator.ValidateProfile(profile);
errorProvider.SetError(emailTextBox, result.GetFirstFieldError("Email") ?? string.Empty);

WPF (INotifyDataErrorInfo)

var result = validator.ValidateProfile(profile);
var emailErrors = result.GetFieldErrors(nameof(UserProfile.Email));

ASP.NET Core (ModelState)

var result = validator.ValidateProfile(profile);
foreach (var entry in result.ToErrorDictionary())
{
    foreach (var error in entry.Value)
    {
        ModelState.AddModelError(entry.Key, error);
    }
}

Complex Object Validation

public class UserProfile
{
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
    public string Password { get; set; }
    public string Website { get; set; }
    public DateTime DateOfBirth { get; set; }
    public decimal Salary { get; set; }
}

var validator = new UserProfileValidator();
var profile = new UserProfile
{
    Email = "john.doe@example.com",
    FirstName = "John",
    LastName = "Doe",
    PhoneNumber = "1234567890",
    Password = "Secure@123",
    Website = "https://example.com",
    DateOfBirth = new DateTime(1990, 1, 1),
    Salary = 50000.00m
};

var result = validator.ValidateProfile(profile);

Built-in Validators

RequiredValidator

var required = CommonValidators.RequiredValidator(fieldName: "DisplayName");
// Validates:
// - Required field

LengthValidator

var length = CommonValidators.LengthValidator(minLength: 3, maxLength: 20, fieldName: "DisplayName");
// Validates:
// - Minimum length (empty values are invalid when minLength > 0)
// - Maximum length (optional)
// - Use RequiredValidator for required fields when minLength is 0

RegexValidator

var regex = CommonValidators.RegexValidator(@"^\d{3}$", "Must be 3 digits", "Code");
// Validates:
// - Regex pattern match (skips empty values)

RangeValidator

var range = CommonValidators.RangeValidator(minValue: 1, maxValue: 10, fieldName: "Rating");
// Validates:
// - Value range

EmailValidator

var emailValidator = CommonValidators.EmailValidator();
// Validates:
// - Required field
// - Email format

NameValidator

var nameValidator = CommonValidators.NameValidator(
    minLength: 2,
    maxLength: 50,
    fieldName: "FirstName"
);
// Validates:
// - Required field
// - Length constraints
// - Valid characters (letters, spaces, hyphens, apostrophes)

PhoneValidator

var phoneValidator = CommonValidators.PhoneValidator(
    requiredLength: 10,
    fieldName: "Phone"
);
// Validates:
// - Required field
// - Numeric characters only
// - Exact length

PasswordValidator

var passwordValidator = CommonValidators.PasswordValidator();
// Validates:
// - Minimum length (8 characters)
// - Contains uppercase letter
// - Contains lowercase letter
// - Contains number
// - Contains special character

UrlValidator

var urlValidator = CommonValidators.UrlValidator();
// Validates:
// - Required field
// - Valid URL format

DateValidator

var dateValidator = CommonValidators.DateValidator(
    minDate: DateTime.Now.AddYears(-120),
    maxDate: DateTime.Now.AddYears(-18)
);
// Validates:
// - Date range

CurrencyValidator

var currencyValidator = CommonValidators.CurrencyValidator(
    minValue: 0,
    maxValue: 1000000
);
// Validates:
// - Non-negative amounts
// - Maximum 2 decimal places
// - Value range

ZipCodeValidator

var zipValidator = CommonValidators.ZipCodeValidator();
// Validates:
// - US ZIP code format (12345 or 12345-6789)
// - Required field

AlphanumericValidator

var alphanumericValidator = CommonValidators.AlphanumericValidator(
    minLength: 3,
    maxLength: 20
);
// Validates:
// - Letters and numbers only
// - Length constraints
// - Required field

IpAddressValidator

var ipValidator = CommonValidators.IpAddressValidator();
// Validates:
// - IPv4 address format
// - Required field

UsernameValidator

var usernameValidator = CommonValidators.UsernameValidator(
    minLength: 3,
    maxLength: 20
);
// Validates:
// - Must start with a letter
// - Letters, numbers, underscores, hyphens allowed
// - Length constraints
// - Required field

CreditCardValidator

var cardValidator = CommonValidators.CreditCardValidator();
// Validates:
// - Credit card number format (13-19 digits)
// - Luhn algorithm checksum
// - Accepts spaces and hyphens
// - Required field

PostalCodeValidator

var postalValidator = CommonValidators.PostalCodeValidator();
// Validates:
// - Canadian postal code format (A1A 1A1)
// - Required field

HexColorValidator

var colorValidator = CommonValidators.HexColorValidator();
// Validates:
// - Hexadecimal color code format (#RRGGBB or #RGB)
// - Required field

Additional Validators

GuidValidator

var guidValidator = CommonValidators.GuidValidator();
// Validates:
// - GUID is not empty

GuidStringValidator

var guidStringValidator = CommonValidators.GuidStringValidator();
// Validates:
// - String is a valid GUID format
// - Required field

EnumValidator

// With explicit values
var enumValidator = CommonValidators.EnumValidator(new[] { "A", "B", "C" });

// With actual enum type
var colorValidator = CommonValidators.EnumValidator<ConsoleColor>();
// Validates:
// - Value is one of the allowed enum values

UuidValidator

var uuidValidator = CommonValidators.UuidValidator();
// Validates:
// - String is a valid UUID (version 1-5)
// - Required field

IsbnValidator

var isbnValidator = CommonValidators.IsbnValidator();
// Validates:
// - ISBN-10 or ISBN-13 format
// - Required field

MacAddressValidator

var macValidator = CommonValidators.MacAddressValidator();
// Validates:
// - MAC address format (00:1A:2B:3C:4D:5E or 00-1A-2B-3C-4D-5E)
// - Required field

TimeValidator

var timeValidator = CommonValidators.TimeValidator();
// Validates:
// - Time format (HH:mm or HH:mm:ss)
// - Required field

JsonValidator

var jsonValidator = CommonValidators.JsonValidator();
// Validates:
// - Valid JSON format
// - Required field

Base64Validator

var base64Validator = CommonValidators.Base64Validator();
// Validates:
// - Valid Base64 encoded string
// - Required field

FilePathValidator

var filePathValidator = CommonValidators.FilePathValidator();
// Validates:
// - Valid file path (no invalid characters)
// - Required field

NullValidator / NotNullValidator

var nullValidator = CommonValidators.NullValidator<string>();
var notNullValidator = CommonValidators.NotNullValidator<string>();
// Validates:
// - Value is null (or not null)

ConfirmValidator

var confirmValidator = CommonValidators.ConfirmValidator(originalValue, "Confirmation");
// Validates:
// - Value matches the original value
// - Required field

EmptyValidator / NotEmptyValidator

var emptyValidator = CommonValidators.EmptyValidator();
var notEmptyValidator = CommonValidators.NotEmptyValidator();
// Validates:
// - Value is empty (or not empty)

Network Validators

InternationalPhoneValidator

var phoneValidator = CommonValidators.InternationalPhoneValidator(allowCountryCode: true);
// Validates:
// - International phone numbers with or without country code
// - Format: +1-555-123-4567 or 5551234567

IpAddressValidator

// Validate IPv4 only
var ipv4Validator = CommonValidators.IpAddressValidator(allowIPv4: true, allowIPv6: false);

// Validate IPv6 only
var ipv6Validator = CommonValidators.IpAddressValidator(allowIPv4: false, allowIPv6: true);

// Validate either
var ipValidator = CommonValidators.IpAddressValidator();
// Validates:
// - IPv4 addresses (e.g., 192.168.1.1)
// - IPv6 addresses (e.g., 2001:0db8:85a3:0000:0000:8a2e:0370:7334)

DomainValidator

var domainValidator = CommonValidators.DomainValidator(allowSubdomains: true, requireTld: true);
// Validates:
// - Domain names (e.g., example.com)
// - Optional subdomains (e.g., www.example.com)
// - Optional TLD requirement

StrictUrlValidator

var urlValidator = CommonValidators.StrictUrlValidator(requireHttps: true, allowLocalhost: false);
// Validates:
// - Absolute URLs
// - Optional HTTPS requirement
// - Optional localhost allowance
// - Valid TLD requirement

JwtValidator

var jwtValidator = CommonValidators.JwtValidator(validateExpiry: false);
// Validates:
// - JWT format (header.payload.signature)
// - Optional expiry validation

ApiKeyValidator

var apiKeyValidator = CommonValidators.ApiKeyValidator(minLength: 32, maxLength: 128);
// Validates:
// - API key length constraints
// - Alphanumeric characters, hyphens, underscores, and periods

Identifier Validators

SsnValidator

var ssnValidator = CommonValidators.SsnValidator();
// Validates:
// - US Social Security Number format
// - Formats: XXX-XX-XXXX, XXX XX XXXX, or XXXXXXXXX

CvvValidator

var cvvValidator = CommonValidators.CvvValidator(CreditCardType.AmericanExpress);
// Validates:
// - Credit card CVV/CVC codes
// - Card-type specific length requirements (Amex: 4 digits, others: 3-4 digits)

CreditCardExpiryValidator

var expiryValidator = CommonValidators.CreditCardExpiryValidator();
// Validates:
// - Credit card expiration dates
// - Formats: MM/YY, MM/YYYY, MM-YY, MM-YYYY
// - Ensures date is in the future

File Validators

FileExtensionValidator

var extValidator = CommonValidators.FileExtensionValidator(new[] { "jpg", "png", "gif" }, caseSensitive: false);
// Validates:
// - File has one of the allowed extensions
// - Optional case sensitivity

MimeTypeValidator

var mimeValidator = CommonValidators.MimeTypeValidator();
// Validates:
// - MIME type format (type/subtype)
// - Examples: text/plain, image/jpeg, application/json

Versioning Validators

SemanticVersionValidator

var semverValidator = CommonValidators.SemanticVersionValidator();
// Validates:
// - Semantic version format (Major.Minor.Patch)
// - Optional prerelease and build metadata
// - Examples: 1.0.0, 1.2.3-beta.1, 2.0.0+build.123

Code Validators

CurrencyCodeValidator

var currencyValidator = CommonValidators.CurrencyCodeValidator();
// Validates:
// - ISO 4217 currency codes
// - Format: 3 uppercase letters (e.g., USD, EUR, GBP)

LanguageCodeValidator

var langValidator = CommonValidators.LanguageCodeValidator();
// Validates:
// - ISO 639-1 language codes
// - Formats: 2-letter code (e.g., en, fr) or with region (e.g., en-US, fr-FR)

CountryCodeValidator

var countryValidator = CommonValidators.CountryCodeValidator(allowAlpha3: true);
// Validates:
// - ISO 3166-1 country codes
// - 2-letter (e.g., US, GB) or 3-letter (e.g., USA, GBR) codes

PostalCodeValidator

var postalValidator = CommonValidators.PostalCodeValidator("US");
// Validates:
// - Country-specific postal code formats
// - Supports: US, CA, GB, DE, FR, IT, AU, NL, ES, SE, CH, JP, IN, BR, RU, CN, MX, AR, ZA, NZ
// - Generic validation for unsupported countries

Location Validators

LatitudeValidator

var latValidator = CommonValidators.LatitudeValidator();
// Validates:
// - Latitude coordinates between -90 and 90
// - Supports decimal degrees

LongitudeValidator

var lonValidator = CommonValidators.LongitudeValidator();
// Validates:
// - Longitude coordinates between -180 and 180
// - Supports decimal degrees

CoordinatesValidator

var coordsValidator = CommonValidators.CoordinatesValidator(", ");
// Validates:
// - Coordinate pairs (latitude, longitude)
// - Customizable separator
// - Example: "40.7128, -74.0060"

TimeZoneValidator

var tzValidator = CommonValidators.TimeZoneValidator();
// Validates:
// - Time zone identifiers
// - Formats: UTC offset (e.g., UTC-5, GMT+3) or IANA (e.g., America/New_York)

Text Validators

LettersOnlyValidator

var lettersValidator = CommonValidators.LettersOnlyValidator(
    allowSpaces: true,
    allowHyphens: true,
    allowApostrophes: true);
// Validates:
// - Strings containing only Unicode letters
// - Optional spaces, hyphens, and apostrophes
// - Supports accented characters (e.g., Cafรฉ, O'Brien)

SlugValidator

var slugValidator = CommonValidators.SlugValidator(maxLength: 100, allowUnderscores: false);
// Validates:
// - URL-friendly slugs
// - Lowercase letters, numbers, and hyphens
// - Optional underscores
// - Optional maximum length

Security Validators

StrongPasswordValidator

var strongPasswordValidator = CommonValidators.StrongPasswordValidator(
    minLength: 8,
    requireUppercase: true,
    requireLowercase: true,
    requireNumber: true,
    requireSpecial: true,
    maxConsecutiveChars: 2);
// Validates:
// - Minimum length
// - Character type requirements (uppercase, lowercase, numbers, special)
// - Maximum consecutive identical characters
// - Fully customizable requirements

Color Validators

ColorValidator

var colorValidator = CommonValidators.ColorValidator();
// Validates:
// - Hex colors: #RRGGBB or #RGB
// - RGB: rgb(255, 255, 255)
// - RGBA: rgba(255, 255, 255, 0.5)
// - HSL: hsl(120, 50%, 50%)
// - HSLA: hsla(120, 50%, 50%, 0.5)

Creating Custom Validators

You can create custom validators by extending the base Validator<T> class:

public static Validator<string> CustomValidator()
{
    return new Validator<string>("CustomField")
        .AddRule(value => !string.IsNullOrEmpty(value), "Value is required")
        .AddRule(value => // your custom rule, "Your error message");
}

Validation Results

The ValidationResult class provides detailed information about validation results:

public class ValidationResult
{
    public bool IsValid { get; set; }
    public List<string> Errors { get; }
    public Dictionary<string, List<string>> FieldErrors { get; }
}

Helper methods are available for UI integration:

var errors = result.GetFieldErrors("Email");
var firstError = result.GetFirstFieldError("Email");

Handling Validation Results

var result = validator.ValidateProfile(profile);

if (!result.IsValid)
{
    // Access general errors
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error: {error}");
    }

    // Access field-specific errors
    foreach (var fieldErrors in result.FieldErrors)
    {
        Console.WriteLine($"Field: {fieldErrors.Key}");
        foreach (var error in fieldErrors.Value)
        {
            Console.WriteLine($"  - {error}");
        }
    }
}

Async Validation

The framework now supports asynchronous validation with the AsyncValidator<T> class. This is useful when you need to perform async operations like database lookups, API calls, or file system checks during validation.

Basic Async Validation

// Create an async validator
var validator = new AsyncValidator<string>("Username")
    .AddRule(value => !string.IsNullOrEmpty(value), "Username is required")
    .AddAsyncRule(async value => await IsUsernameAvailableAsync(value), "Username is already taken");

// Validate asynchronously
var result = await validator.ValidateAsync("john_doe");

if (result.IsValid)
{
    Console.WriteLine("Username is available!");
}

// Helper async method
private async Task<bool> IsUsernameAvailableAsync(string username)
{
    // Simulate async database check
    await Task.Delay(100);
    return username != "admin";
}

Mixed Sync and Async Rules

var validator = new AsyncValidator<string>("Email")
    .AddRule(value => !string.IsNullOrEmpty(value), "Email is required")
    .AddRule(value => value.Contains("@"), "Invalid email format")
    .AddAsyncRule(async value => await IsEmailAvailableAsync(value), "Email is already registered");

var result = await validator.ValidateAsync("john@example.com");

Merging Async Validation Results

var emailResult = await emailValidator.ValidateAsync(email);
var usernameResult = await usernameValidator.ValidateAsync(username);
var combinedResult = await emailResult.MergeAsync(usernameResult);

// Or merge multiple async results at once
var allResults = await AsyncValidationExtensions.MergeAsync(
    new[] { emailResult, usernameResult, passwordResult });

.NET Ecosystem Compatibility

The framework provides seamless integration with all major .NET UI platforms, making it easy to use validation across your entire application stack.

ASP.NET Core Integration

The framework integrates with ASP.NET Core's ModelState system for seamless validation in web applications.

// In your controller
var validator = new UserValidator();
var result = validator.Validate(userModel);

// Add errors to ModelState
result.AddToModelState(ModelState);

// Or return a BadRequest with validation errors
return result.ToBadRequest();

// With custom message
return result.ToBadRequest("Validation failed");

// Check validity and add to ModelState
if (!result.EnsureValid(ModelState))
{
    return BadRequest(ModelState);
}

// Using the ValidateModelAttribute for automatic validation
[ValidateModel]
public IActionResult Create(UserModel model)
{
    // ModelState is automatically populated with validation errors
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    return Ok();
}

// Base class for validatable models
public class UserModel : ValidatableModel
{
    public string Email { get; set; }
    public string Password { get; set; }
    
    public override ValidationResult Validate()
    {
        var validator = new Validator<UserModel>("User");
        validator.AddRule(m => !string.IsNullOrEmpty(m.Email), "Email is required", nameof(Email));
        validator.AddRule(m => CommonValidators.EmailValidator().Validate(m.Email).IsValid, "Invalid email", nameof(Email));
        return validator.Validate(this);
    }
}

WPF Integration

The framework integrates with WPF's validation system and INotifyDataErrorInfo interface.

// Extension methods for WPF controls
textBox.SetValidationError(result, nameof(User.Email));
textBox.SetFirstValidationError(result, nameof(User.Email));
textBox.ClearValidationError();

// Apply validation to multiple controls
var controlMappings = new Dictionary<string, Control>
{
    { nameof(User.Email), emailTextBox },
    { nameof(User.Name), nameTextBox }
};
result.ApplyToControls(controlMappings);

// Base class for validatable ViewModels
public class UserViewModel : ValidatableViewModel
{
    private string _email;
    public string Email
    {
        get => _email;
        set => SetProperty(ref _email, value);
    }
    
    public override ValidationResult Validate()
    {
        var validator = new Validator<UserViewModel>("User");
        validator.AddRule(vm => !string.IsNullOrEmpty(vm.Email), "Email is required", nameof(Email));
        validator.AddRule(vm => CommonValidators.EmailValidator().Validate(vm.Email).IsValid, "Invalid email", nameof(Email));
        return validator.Validate(this);
    }
}

// WPF ValidationRule for XAML
public class EmailValidationRule : WpfValidationRule<string>
{
    protected override ValidationResult Validate(string value, CultureInfo cultureInfo)
    {
        return CommonValidators.EmailValidator().Validate(value);
    }
}

// In XAML
<TextBox Text="{Binding Email, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}">
    <TextBox.ValidationRules>
        <local:EmailValidationRule />
    </TextBox.ValidationRules>
</TextBox>

// Attached property for validation
<TextBox local:ValidationBehavior.Validator="{Binding EmailValidator}" 
         local:ValidationBehavior.FieldName="Email" />

Windows Forms Integration

The framework integrates with Windows Forms ErrorProvider for displaying validation errors.

// Extension methods for WinForms controls
errorProvider.SetValidationError(textBox, result, nameof(User.Email));
errorProvider.SetAllValidationErrors(this, result);
errorProvider.ClearValidationError(textBox);

// Apply validation to multiple controls
var controlMappings = new Dictionary<string, Control>
{
    { nameof(User.Email), emailTextBox },
    { nameof(User.Name), nameTextBox }
};
result.ApplyToControls(controlMappings);

// Validate a control
errorProvider.ValidateControl(emailTextBox, emailValidator, nameof(User.Email));

// Validate entire form
errorProvider.ValidateForm(this, userValidator);

// Base class for validatable forms
public class UserForm : ValidatableForm
{
    public UserForm()
    {
        // ErrorProvider is automatically created
    }
    
    protected override ValidationResult OnValidate()
    {
        var validator = new Validator<User>("User");
        validator.AddRule(u => !string.IsNullOrEmpty(u.Email), "Email is required", nameof(User.Email));
        return validator.Validate(GetUserFromForm());
    }
}

// Validatable controls
<local:ValidatableTextBox Validator="{emailValidator}" FieldName="Email" />
<local:ValidatableComboBox Validator="{countryValidator}" FieldName="Country" />

Blazor Integration

The framework integrates with Blazor's EditContext for form validation.

// Extension methods for Blazor EditContext
result.AddToEditContext(EditContext);
result.EnsureValid(EditContext);

// Convert to error dictionary
errors = result.ToBlazorErrorDictionary();

// Convert to error list
errorMessages = result.ToErrorList();

// Base class for validatable components
public class UserComponent : ValidatableComponentBase
{
    [Parameter]
    public User User { get; set; }
    
    protected override ValidationResult OnValidate()
    {
        var validator = new Validator<User>("User");
        validator.AddRule(u => !string.IsNullOrEmpty(u.Email), "Email is required", nameof(User.Email));
        return validator.Validate(User);
    }
}

// Validatable input component
<ValidatableInput @bind-Value="User.Email" 
                  Validator="emailValidator" 
                  FieldName="Email" />

// Validatable form
<ValidatableForm Model="User" Validator="userValidator" 
                  ValidationResultChanged="OnValidationChanged">
    <ChildContent>
        <ValidatableInput @bind-Value="User.Email" FieldName="Email" />
        <ValidationMessage FieldName="Email" />
        <ValidationSummary />
    </ChildContent>
</ValidatableForm>

// Validation message component
<ValidationMessage ValidationResult="ValidationResult" FieldName="Email" />

// Validation summary component
<ValidationSummary ValidationResult="ValidationResult" />

// Validation state component
<ValidationState EditContext="EditContext" ValidationResult="ValidationResult">
    <ValidContent>Form is valid!</ValidContent>
    <InvalidContent>Please fix the errors</InvalidContent>
</ValidationState>

.NET MAUI Integration

The framework integrates with .NET MAUI's VisualElement system for mobile and desktop applications.

// Extension methods for MAUI VisualElements
entry.SetValidationError(result, nameof(User.Email));
entry.SetFirstValidationError(result, nameof(User.Email));
entry.ClearValidationError();

// Apply validation to multiple elements
var elementMappings = new Dictionary<string, VisualElement>
{
    { nameof(User.Email), emailEntry },
    { nameof(User.Name), nameEntry }
};
result.ApplyToElements(elementMappings);

// Convert to MAUI error dictionary
errors = result.ToMauiErrorDictionary();

// Convert to MAUI error list
errorMessages = result.ToMauiErrorList();

// Check validity and display errors
result.EnsureValid(page); // Shows alert with errors

// Base class for validatable ViewModels
public class UserViewModel : ValidatableViewModel
{
    private string _email;
    public string Email
    {
        get => _email;
        set => SetProperty(ref _email, value);
    }
    
    public override ValidationResult Validate()
    {
        var validator = new Validator<UserViewModel>("User");
        validator.AddRule(vm => !string.IsNullOrEmpty(vm.Email), "Email is required", nameof(Email));
        return validator.Validate(this);
    }
}

// Validatable Entry control
<local:ValidatableEntry Text="{Binding Email}" 
                        Validator="{Binding EmailValidator}" 
                        FieldName="Email" />

// Validatable Editor control
<local:ValidatableEditor Text="{Binding Description}" 
                          Validator="{Binding DescriptionValidator}" 
                          FieldName="Description" />

// Validatable ContentPage
public class UserPage : ValidatableContentPage
{
    public UserPage(UserViewModel viewModel)
    {
        BindingContext = viewModel;
        Validator = viewModel;
    }
    
    private async void OnSaveClicked(object sender, EventArgs e)
    {
        await ValidateAsync();
        if (IsValid)
        {
            await DisplayAlert("Success", "User saved!", "OK");
        }
        else
        {
            await DisplayValidationErrorsAsync();
        }
    }
}

// Attached properties for validation
<Entry local:ValidationBehavior.Validator="{Binding EmailValidator}" 
       local:ValidationBehavior.FieldName="Email" />

// Model binding with validation
emailEntry.BindWithValidation(User, nameof(User.Email), emailValidator);

Advanced Usage

Using ValidationBuilder

var builder = new ValidationBuilder<UserProfile>()
    .AddValidation("Email", p => CommonValidators.EmailValidator().Validate(p.Email))
    .AddValidation("FirstName", p => CommonValidators.NameValidator().Validate(p.FirstName));

var result = builder.Validate(userProfile);

Merging Validation Results

var result1 = emailValidator.Validate(email);
var result2 = nameValidator.Validate(name);
var combinedResult = result1.Merge(result2);

Best Practices

  1. Field Names: Always provide meaningful field names for better error messages
var validator = CommonValidators.EmailValidator(fieldName: "Work Email");
  1. Custom Validation Rules: Keep rules simple and focused
.AddRule(value => value.Length > 0, "Value is required")
  1. Error Messages: Write clear, actionable error messages
"Password must contain at least one uppercase letter"
  1. Validation Groups: Organize related validations using ValidationBuilder
var builder = new ValidationBuilder<UserProfile>()
    .AddValidation("PersonalInfo", ValidatePersonalInfo)
    .AddValidation("ContactInfo", ValidateContactInfo);

Contributing

Contributions are welcome! Feel free to:

  1. Fork the repository
  2. Create a feature branch
  3. Submit a pull request

Please ensure your code follows the existing style and includes appropriate tests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

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.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.2 139 6/20/2026

Version 2.0.1: Added async validation support (AsyncValidator, AsyncValidationRule), new validators (Guid, UUID, ISBN, MAC Address, JSON, Base64, Enum, etc.), improved CI/CD pipeline, enhanced error handling, and NuGet Trusted Publishing deployment.