Phema.Validation 3.0.5

C# strongly typed validation library for .NET

There is a newer version of this package available.
See the version list below for details.
This package is considered a SemVer 2.0.0 package as it has a package dependency on SemVer 2.0.0 package(s).
This package will only be available to download with SemVer 2.0.0 compatible NuGet clients, such as Visual Studio 2017 (version 15.3) and above or NuGet client 4.3.0 and above. Read more
Install-Package Phema.Validation -Version 3.0.5
dotnet add package Phema.Validation --version 3.0.5
<PackageReference Include="Phema.Validation" Version="3.0.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Phema.Validation --version 3.0.5
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Phema.Validation

Build Status
Nuget

C# strongly typed expression-based validation library for .NET

Installation

$> dotnet add package Phema.Validation

Usage (example)

// Add `IValidationContext` as scoped service
services.AddValidation(options => ...);

// Get or inject
var validationContext = serviceProvider.GetRequiredService<IValidationContext>();

// Use with a lot of validation rules (Check for Phema.Validation.Conditions namespace)
validationContext.When(person, p => p.Name)
  .IsNullOrWhitespace()
  .Is(name => ...Custom checks...)
  .AddError("Name must be set");

// Get validation details. Null if valid
var details = validationContext.When(person, p => p.Age)
  .IsNull()
  .AddError("Age must be set");

// 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

// Validate collections
validationContext.When(person, p => p.Children)
  .IsEmpty()
  .AddError("You have no children");

// Check if context is valid
validationContext.IsValid();
validationContext.EnsureIsValid(); // If invalid throw ValidationContextException

// Check concrete validation details
validationContext.IsValid(person, p => p.Age);

// Create nested validationContext
// It will be `Child.*ValidationPart*` validation key
ValidateChild(validationContext.CreateScope(parent, p => p.Child))

// Combine paths
// It will be `Address.Locations[0].*ValidationPart*` validation key
ValidateLocation(validationContext.CreateScope(person, p => p.Address.Locations[0]))

// It will be `Address.Locations[0].Latitude`
validationContext.When(person, p => p.Address.Locations[0].Latitude)
  .Is(latitude => ...)
  .AddError("Some custom check failed");
  
// Override validation parts with `DataMemberAttribute`
[DataMember(Name = "age")]
public int Age { get; set; }

Performance

  • Simpler expression = less costs
  • Try to use non-expression extensions in hot paths
  • Use CreateScope to not to repeat chained member calls (x =&gt; x.Property1.Property2[0].Property3)
  • Expression-based When extensions use expression compilation to get value (Invoke)
  • Composite indexers x =&gt; x.Collection[indexProvider.Parsed.Index] use expression compilation (DynamicInvoke)
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)

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 |

Phema.Validation

Build Status
Nuget

C# strongly typed expression-based validation library for .NET

Installation

$> dotnet add package Phema.Validation

Usage (example)

// Add `IValidationContext` as scoped service
services.AddValidation(options => ...);

// Get or inject
var validationContext = serviceProvider.GetRequiredService<IValidationContext>();

// Use with a lot of validation rules (Check for Phema.Validation.Conditions namespace)
validationContext.When(person, p => p.Name)
  .IsNullOrWhitespace()
  .Is(name => ...Custom checks...)
  .AddError("Name must be set");

// Get validation details. Null if valid
var details = validationContext.When(person, p => p.Age)
  .IsNull()
  .AddError("Age must be set");

// 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

// Validate collections
validationContext.When(person, p => p.Children)
  .IsEmpty()
  .AddError("You have no children");

// Check if context is valid
validationContext.IsValid();
validationContext.EnsureIsValid(); // If invalid throw ValidationContextException

// Check concrete validation details
validationContext.IsValid(person, p => p.Age);

// Create nested validationContext
// It will be `Child.*ValidationPart*` validation key
ValidateChild(validationContext.CreateScope(parent, p => p.Child))

// Combine paths
// It will be `Address.Locations[0].*ValidationPart*` validation key
ValidateLocation(validationContext.CreateScope(person, p => p.Address.Locations[0]))

// It will be `Address.Locations[0].Latitude`
validationContext.When(person, p => p.Address.Locations[0].Latitude)
  .Is(latitude => ...)
  .AddError("Some custom check failed");
  
// Override validation parts with `DataMemberAttribute`
[DataMember(Name = "age")]
public int Age { get; set; }

Performance

  • Simpler expression = less costs
  • Try to use non-expression extensions in hot paths
  • Use CreateScope to not to repeat chained member calls (x =&gt; x.Property1.Property2[0].Property3)
  • Expression-based When extensions use expression compilation to get value (Invoke)
  • Composite indexers x =&gt; x.Collection[indexProvider.Parsed.Index] use expression compilation (DynamicInvoke)
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)

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 |

This package is not used by any popular GitHub repositories.

Version History

Version Downloads Last updated
3.1.10 24 10/12/2019
3.1.9 72 9/27/2019
3.1.8 67 9/25/2019
3.1.7 90 9/15/2019
3.1.6 47 9/8/2019
3.1.5 37 9/7/2019
3.1.4 36 9/7/2019
3.1.3 57 9/7/2019
3.1.2 36 8/25/2019
3.1.1 35 8/24/2019
3.1.0 36 8/23/2019
3.0.9 36 8/23/2019
3.0.8 37 8/22/2019
3.0.7 38 8/16/2019
3.0.6 39 7/30/2019
3.0.5 37 7/29/2019
3.0.4 37 7/29/2019
3.0.3 36 7/28/2019
3.0.2 36 7/21/2019
Show less