Phema.Validation
3.0.7
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package Phema.Validation --version 3.0.7
NuGet\Install-Package Phema.Validation -Version 3.0.7
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="Phema.Validation" Version="3.0.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Phema.Validation --version 3.0.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Phema.Validation, 3.0.7"
#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.
// Install Phema.Validation as a Cake Addin #addin nuget:?package=Phema.Validation&version=3.0.7 // Install Phema.Validation as a Cake Tool #tool nuget:?package=Phema.Validation&version=3.0.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Phema.Validation
C# strongly typed expression-based validation library for .NET built on extension methods
Installation
$> dotnet add package Phema.Validation
Usage (example)
// Add `IValidationContext` as scoped service
services.AddValidation(options => ...);
// Get or inject
var validationContext = serviceProvider.GetRequiredService<IValidationContext>();
// Validation key will be `Name`
validationContext.When(person, p => p.Name)
.Is(name => name == null)
.AddError("Name must be set");
// Validation key will be `Address.Locations[0].Latitude`
validationContext.When(person, p => p.Address.Locations[0].Latitude)
.Is(latitude => ...custom check...)
.AddError("Some custom check failed");
// Override validation parts with `DataMemberAttribute`
[DataMember(Name = "name")]
public string Name { get; set; }
Validation conditions
// Check for Phema.Validation.Conditions namespace
validationContext.When(person, p => p.Name)
.IsNullOrWhitespace()
.AddError("Name must be set");
// Use multiple conditions (joined with OR)
validationContext.When(person, p => p.Name)
.IsNull()
.HasLengthGreater(20)
// .IsNotNull()
// .IsEqual()
// .IsMatch(regex)
.AddError("Name is invalid");
Validation details
// Null if valid
var validationDetails = validationContext.When(person, p => p.Age)
.IsNull()
.AddError("Age must be set");
// Use deconstruction
var (key, message) = validationContext.When(person, p => p.Age)
.IsNull()
.AddError("Age must be set");
Check validation
// Override default ValidationSeverity
validationContext.ValidationSeverity = ValidationSeverity.Warning;
// Throw exception when details severity greater than ValidationContext.ValidationSeverity
validationContext.When(person, p => p.Address)
.IsNull()
.AddFatal("Address is not presented!!!"); // If invalid throw ValidationConditionException
// Check if context is valid
validationContext.IsValid();
validationContext.EnsureIsValid(); // If invalid throw ValidationContextException
// Check concrete validation details
validationContext.IsValid(person, p => p.Age);
validationContext.EnsureIsValid(person, p => p.Age);
Validation scopes
- Use scopes when you need to have:
- Same nested validation path multiple times
- Empty validation details collection (syncing with parent context/scope)
- ValidationSeverity override
// Validation key will be `Child.*ValidationPart*`
ValidateChild(validationContext.CreateScope(parent, p => p.Child))
// Validation key will be `Address.Locations[0].*ValidationPart*`
ValidateLocation(validationContext.CreateScope(person, p => p.Address.Locations[0]))
High performance with non-expression constructions
validationContext.When("key", value)
.IsNull()
.AddError("Value is null");
validationContext.CreateScope("key");
validationContext.IsValid("key");
validationContext.EnsureIsValid("key");
Benchmarks (i7 9700k 3.60 GHz, 16Gb 3400 MHz)
- Simpler expression = less costs
- Try to use non-expression extensions in hot paths
- Use
CreateScope
to not to repeat chained member calls (x => x.Property1.Property2[0].Property3
) - Expression-based
When
extensions use expression compilation to get value (Invoke) - Composite indexers
x => x.Collection[indexProvider.Parsed.Index]
use expression compilation (DynamicInvoke)
Non-expression validation
Method | Mean | Error | StdDev | Max | Iterations |
---|---|---|---|---|---|
Simple | 1.421 us | 0.0071 us | 0.0653 us | 1.581 us | 925.0 |
CreateScope | 1.287 us | 0.0046 us | 0.0431 us | 1.394 us | 971.0 |
IsValid | 1.350 us | 0.0042 us | 0.0401 us | 1.444 us | 986.0 |
EnsureIsValid | 1.374 us | 0.0042 us | 0.0401 us | 1.475 us | 987.0 |
Expression validation
Method | Mean | Error | StdDev | Max | Iterations |
---|---|---|---|---|---|
SimpleExpression | 52.181 us | 0.2692 us | 2.5770 us | 60.106 us | 998.0 |
ChainedExpression | 59.643 us | 0.3316 us | 3.1521 us | 68.800 us | 984.0 |
ArrayAccessExpression | 73.636 us | 0.4902 us | 4.6804 us | 89.787 us | 993.0 |
ChainedArrayAccessExpression | 80.645 us | 0.5602 us | 5.3484 us | 98.931 us | 993.0 |
ChainedArrayAccess_DynamicInvoke_Expression | 288.098 us | 0.9826 us | 9.3864 us | 317.175 us | 994.0 |
CreateScope_SimpleExpression | 4.443 us | 0.0156 us | 0.1469 us | 4.838 us | 965.0 |
CreateScope_ChainedExpression | 5.467 us | 0.0301 us | 0.2849 us | 6.237 us | 973.0 |
IsValid_Empty | 4.642 us | 0.0241 us | 0.2275 us | 5.275 us | 970.0 |
IsValid_Expression | 4.659 us | 0.0192 us | 0.1826 us | 5.138 us | 982.0 |
EnsureIsValid_Expression | 4.664 us | 0.0262 us | 0.2496 us | 5.450 us | 991.0 |
Product | Versions 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 was computed. 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. |
.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.
-
.NETStandard 2.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 3.0.0-preview7.19362.4)
- Microsoft.Extensions.Options (>= 3.0.0-preview7.19362.4)
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 |
---|---|---|
3.1.10 | 1,022 | 10/12/2019 |
3.1.9 | 1,073 | 9/27/2019 |
3.1.8 | 993 | 9/25/2019 |
3.1.7 | 360 | 9/15/2019 |
3.1.6 | 321 | 9/8/2019 |
3.1.5 | 303 | 9/7/2019 |
3.1.4 | 303 | 9/7/2019 |
3.1.3 | 325 | 9/7/2019 |
3.1.2 | 308 | 8/25/2019 |
3.1.1 | 295 | 8/24/2019 |
3.1.0 | 298 | 8/23/2019 |
3.0.9 | 302 | 8/23/2019 |
3.0.8 | 314 | 8/22/2019 |
3.0.7 | 298 | 8/16/2019 |
3.0.6 | 332 | 7/30/2019 |
3.0.5 | 295 | 7/29/2019 |
3.0.4 | 317 | 7/29/2019 |
3.0.3 | 304 | 7/28/2019 |
3.0.2 | 301 | 7/21/2019 |