Qowaiv.Validation.DataAnnotations 4.0.0

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

Qowaiv DataAnnotations based validation

Provides an data annotations based implementation of the Qowaiv.Validation.Abstractions.IValidator and data annotation attributes.

Annotated model validator

The AnnotatedModelValidator validates a model using its data annotations. It returns a Result<TModel> of the validated model:

var validator = new AnnotatedModelValidator<SomeModel>();
Result<SomeModel> result = validator.Validate(model);

Validation messages

Qowaiv.Validation.DataAnnotations.ValidationMessage inherits Microsoft's ValidationResult, and implements Qowaiv.Validation.Abstractions.IValidationMessage. This allows the creation of messages with different severities:

var none = ValidationMessage.None; // returns null, but for telling the story ValidationMessage.None is preferred.
var info = ValidationMessage.Info(message, args);
var warn = ValidationMessage.Warning(message, args);
var error = ValidationMessage.Error(message, args);

Required modifier

The required modifier is available since C# 11. When a model has a property with a required modifier, it is considered being decorated with a [Required] attribute via the required modifier when the property:

  1. is a reference type
  2. lacks a nullable (?) annotation

So in this example:

public class Model
{
    public required string RequiredByModifier { get; init; }

    public required string? Optional { get; init; }

    [Required(AllowEmptyStrings = true)]
    public required string AllowStringEmpty {get; init; }
}

The first property is considered required by the AnnotatedModelValidator, and the second one is considered optional. The third one is also considered required, but via the attribute it was decorated with, not because of the required modifier.

Validation attributes

Multiple [System.ComponentModel.DataAnnotations.Validation] attributes can be used to decorate models.

Mandatory

The [Required] attribute does not work for value types. The [Mandatory] attribute does. The default value of the struct is not valid. It also is not valid for the Unknown value, unless that is explicitly allowed.

public class Model
{
    [Mandatory(AllowUnknownValue = true)]
    public EmailAddress Email { get; init; }

    [Mandatory()]
    public string SomeString { get; init; }
}

Any

The [Required] attribute does not work (well) for collections. The [Any] attribute does. It is only valid if the collection contains at least one item.

public class Model
{
    [Any()]
    public List<int> Numbers { get; init; }
}

Allowed values

The [Allowed<TValue>] attribute allows to define a subset of allowed values. It supports type converters to get the allowed values based on a primitive value.

public class Model
{
    [Allowed<Country>("DE", "FR", "GB")]
    public Country CountryOfBirth { get; init; }
}

Forbidden values

The [Forbidden<TValue>] attribute allows to define a subset of forbidden values. It supports type converters to get the forbidden values based on a primitive value.

public class Model
{
    [Forbidden<Country>("US", "IR")]
    public Country CountryOfBirth { get; init; }
}

Defined enum values only

The [DefinedOnly<TEnum>] attribute limits the allowed values to defined enums only. By default it supports all possible combinations of defined enums when dealing with flags, but that can be restricted by setting OnlyAllowDefinedFlagsCombinations to true.

public class Model
{
    [DefinedOnly<SomeEnum>(OnlyAllowDefinedFlagsCombinations = false)]
    public SomeEnum CountryOfBirth { get; init; }
}

In future

The [InFuture] attributes requires the DateTime, DateTimeOffset, Date, DateOnly, or Year value to be in the future. The current time is resolved using Qowaiv.Clock.UtcNow().

public class Model
{
    [InFuture]
    public DateOnly? ExpiryDate { get; init; }
}

In past

The [InPast] attributes requires the DateTime, DateTimeOffset, Date, DateOnly, or Year value to be in the past. The current time is resolved using Qowaiv.Clock.UtcNow().

public class Model
{
    [InPast]
    public DateOnly DateOfBirth { get; init; }
}

Items validation

The [Items<TValidator>] attribute to define a validation attribute to apply on all items of a collection. This is useful in multiple cases:

public class Model
{
    [Items<Mandatory>] // ensures none of the items is null or empty
    public string[] Names { get; init; } = [];

    [Items<Allowed<int>(42, 2017)] // ensures that all items have either the value 42 or 2017.
    public int[] Numbers { get; init; } = [];
}

By defining either ErrorMessage or both ErrorMessageResourceName and ErrorMessageResourceType, those values are set to the TValidator allowing full control of the error message generation.

Is finite

The [IsFinite] attribute validates that the floating point value of the field represents a finite (e.a. not NaN, or infinity).

public class Model
{
    [IsFinite]
    public double Number { get; init; }
}

Skip validation

The [SkipValidation] attribute allows to skip the validation of property or type.

[SkipValidation]
public class Model
{
    [SkipValidation]
    public double Number { get; init; }
}

Multiple of

The [MultipleOf] attribute validates that the value of a field is a multiple of the specified factor.

public class Model
{
    [MultipleOf(0.001)]
    public Amount Total { get; init; }
}

Not in future

The [NotInFuture] attributes requires the DateTime, DateTimeOffset, Date, DateOnly, or Year value not to be in the future. The current time is resolved using Qowaiv.Clock.UtcNow().

public class Model
{
    [InFuture]
    public DateTime CreationTime { get; init; }
}

Not in past

The [NotInPast] attributes requires the DateTime, DateTimeOffset, Date, DateOnly, or Year value not to be in the past. The current time is resolved using Qowaiv.Clock.UtcNow().

public class Model
{
    [InPast]
    public DateOnly Start { get; init; }
}

Optional

The [Optional] attribute indicates explicitly that a field is optional.

public class Model
{
    [Optional]
    public string? Message { get; init; }
}

Unique values

The [Unique<Value>] attribute validates that all items of the collection are distinct. If needed, a custom IEqualityComparer<Value> comparer can be defined.

public class Model
{
    [Unique<int>(typeof(CustomEqualityComparer))]
    public IEnumerable<int> Numbers { get; init; }
}

Validates attribute

The [Validates] attribute is designed to help the QW0102 to report on misusage of the attribute. By decorating an [Validation] attribute the analyzer knows on which member types the attribute can be set.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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 Qowaiv.Validation.DataAnnotations:

Package Downloads
Qowaiv.Validation.TestTools

Qowaiv Validation supports a generic interface for (domain) model validation.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.0.0 1,110 6/5/2025
3.0.0 16,631 11/19/2024
2.0.0 18,281 6/28/2024
1.4.0 24,136 8/4/2023
1.3.0 31,922 3/7/2023
1.0.1 15,451 11/8/2022
1.0.0 5,678 7/12/2022
0.2.4 4,104 6/29/2022
0.2.3 496 6/28/2022
0.2.2 6,158 5/13/2022
0.2.1 10,825 4/13/2022
0.2.0 7,673 12/31/2021
0.1.1 13,475 9/10/2021
0.1.0 627 8/31/2021
0.0.4 2,496 7/2/2021
0.0.3 5,903 5/26/2020
0.0.2 3,185 11/1/2019
0.0.1 1,696 7/30/2019

v4.0.0
- Validate public fields.
- Support primitives of the same type on [ValueOf<TValue>] attributes.
- Support requiredness via the required modifier.
- Introduction of [InPast] valiation attribute.
- Introduction of [InFuture] valiation attribute.
- Introduction of [NotInPast] valiation attribute.
- Introduction of [NotInFuture] valiation attribute.
- Introduction of [Items<TValidator>] to define a validator on the items of a collection.
- Introduction of [SkipValidation] to explictly skip validation of types and properties.
- Introduction of the [Validates(type)] attribute to decorate [Validation] attributes.
- Qowaiv.Validation.DataAnnotations.ValidationMessage.None returns null. (BREAKING)
- Refactor annotations resolving.
- Dropped AnnotatedModel. (BREAKING)
- Dropped AnnotatedProperty. (BREAKING)
- Dropped AnnotatedValidator. (BREAKING)
- Drop support on ValidationAttributes defined on types. (BREAKING)
- Update to Qowaiv v7.4.3.
v3.0.0
- Introduction of AllowedAttribute<T> as alternative to AllowedValuesAttribute.
- Introduction of DefinedOnlyAttribute<T> as alternative to DefinedEnumValuesOnlyAttribute.
- Introduction of ForbiddenAttribute<T> as alternative to ForbiddenValuesAttribute.
- Introduction of UniqueAttribute<T> as alternative to DistinctValuesAttribute.
- Marked AllowedValuesAttribute as obsolete.
- Marked DefinedEnumValuesOnlyAttribute as obsolete.
- Marked DistinctValuesAttribute as obsolete.
- Marked ForbiddenValuesAttribute as obsolete.
- Add .NET 9.0 target.
- Drop .NET 5.0, NET6.0, NET7.0 targets. (BREAKING)
- Drop binary serialization on exceptions. (BREAKING)
v2.0.0.
- Drop support .NET 5.0 and .NET 7.0. (breaking)
- Update to Qowaiv v7.0.0. (breaking)
- Introduction of [IsFinite] validation attribute.
- Introduction of [Length.AtLeast], [Length.AtMost], [Length.InRange].
- Introduction of [Collection.AtLeast], [Collection.AtMost], [Collection.InRange].
- Introduction of [Size.AtLeast], [Size.AtMost], [Size.InRange].
v1.4.0
- Introduced [MultipleOf] validation attribute. #69
- Marked [NestedModel] attribute as obsolete. #70
v1.3.0
- Support .NET 7.0. #62
v1.0.1
- Inaccessible properties do not crash but validate as invalid #58
- Indexed properties are ignored
v1.0.0
- Properties are considered validatable objects without [NestedModel] attribute #55
- Removed unused properties from NestedModel
v0.2.4
- Roll back of change #53
v0.2.3
- All models are considered to be nested. #52
- Fix crash on validation models with properties with generic types. #53
v0.2.2
- Mandatory attribute supports Dutch messages. #51
v0.2.1
- Nullable anotations. #48
v0.2.0
- Updated Qowaiv dependency.
v0.1.1
- Decorate pure methods with attribute (#38)
v0.1.0
- Qowaiv.Validation.Abstractions dependency
v0.0.4
- Fix double dots in paths for nested properties.