Syrx.Validation
2.0.0
dotnet add package Syrx.Validation --version 2.0.0
NuGet\Install-Package Syrx.Validation -Version 2.0.0
<PackageReference Include="Syrx.Validation" Version="2.0.0" />
paket add Syrx.Validation --version 2.0.0
#r "nuget: Syrx.Validation, 2.0.0"
// Install Syrx.Validation as a Cake Addin #addin nuget:?package=Syrx.Validation&version=2.0.0 // Install Syrx.Validation as a Cake Tool #tool nuget:?package=Syrx.Validation&version=2.0.0
Syrx.Validation
A tiny little library with a very simple precondition checker and a handful of validation attributes.
What
The precondition checker the Contract
class is probably the most useful as it can be used by any method. The Validator
is pretty useful too, but really only useful for POCOs that are decorated with validation attributes.
Why
Checking conditions in your code is a good thing but it can get really verbose really quickly and ruin the readbility/intent of your code. More often than not, precondition checks take the form of multiline if (condition) throw exception
statements. We wrote this library to convert the multiline statements into single line statements and give you control over which exceptions are thrown when the condition fails.
Example
In one of the finest traditions of our craft, let's take a look at a contrived and trivial example.
Let's assume we have a basic Person
class which we'll be saving to a database. Seems pretty straightforward, right? Here's what the Person
looks like without any validation.
No validation
public class Person
{
public string Name { get; }
public DateTime DateOfBirth { get; }
public Person(string name, DateTime dateOfBirth)
{
Name = name;
DateOfBirth = dateOfBirth;
}
}
What could go wrong?
Hold my beer...
We said earlier we'd be saving the Person
to a database. Here - in no particular order - are a couple of things that could go wrong.
- No name supplied. Oops.
- Name is supplied to the class. It's 51 characters long but the field on the table can only hold 50. Oops.
- DateOfBirth is equal to either DateTime.MinValue, DateTime.MaxValue or is sometime in the future. Oops.
Vanilla Validation
Okay, so we want to catch those pesky validation problems while we instantiate our Person
. Using the traditional if (condition) throw exception
approach, our class might now look like this which - in my humble opinion - ain't too cool.
While it does the job of catching validation problems, it's caused our simple class to look quite a bit less simple.
The premise behind the if statements is if (false) throw exception
.
public class Person
{
public string Name { get; }
public DateTime DateOfBirth { get; }
public Person(string name, DateTime dateOfBirth)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name));
}
if (name.Length >= 50)
{
throw new ArgumentOutOfRangeException(nameof(name));
}
if (dateOfBirth == DateTime.MinValue ||
dateOfBirth == DateTime.MaxValue ||
dateOfBirth > DateTime.Now)
{
throw new ArgumentOutOfRangeException(nameof(dateOfBirth));
}
Name = name;
DateOfBirth = dateOfBirth;
}
}
Better, I think.
Using the Contract
precondtion checker we can collapse those conditions into much simpler statements - require the condition to be true, otherwise throw an exception.
using static Syrx.Validation.Contract;
public class Person
{
public string Name { get; }
public DateTime DateOfBirth { get; }
public Person(string name, DateTime dateOfBirth)
{
Throw<ArgumentNullException>(!string.IsNullOrWhiteSpace(name), nameof(name));
Throw<ArgumentOutOfRangeException>(name.Length <= 50, nameof(name));
Throw<ArgumentOutOfRangeException>(!(dateOfBirth == DateTime.MinValue ||
dateOfBirth == DateTime.MaxValue ||
dateOfBirth > DateTime.Now), nameof(dateOfBirth));
Name = name;
DateOfBirth = dateOfBirth;
}
}
Now with added delegates!
Useful as the Throw<T>
method is, it can be a little limiting when you need very fine control over the exception. Never fear though - the latest version now allows you to pass your own Func<TException>
delegate to be invoked if your required condition evaluates to false.
Using our super trivial example again, our validation can be re-written again. It's functionally equivalent, and a couple more keystrokes, but shows how you can roll your own exception invocation.
using static Syrx.Validation.Contract;
public class Person
{
public string Name { get; }
public DateTime DateOfBirth { get; }
public Person(string name, DateTime dateOfBirth)
{
Throw(!string.IsNullOrWhiteSpace(name), () => new ArgumentNullException(nameof(name)));
Throw(name.Length <= 50, () => new ArgumentOutOfRangeException(nameof(name)));
Throw(!(dateOfBirth == DateTime.MinValue ||
dateOfBirth == DateTime.MaxValue ||
dateOfBirth > DateTime.Now), () => new ArgumentOutOfRangeException(nameof(dateOfBirth)));
Name = name;
DateOfBirth = dateOfBirth;
}
}
That's great! Where can I get this?
Nuget, of course.
Install-Package Syrx.Validation
Anything else I should know?
First, I find that the Contract.Throw<T>
method is insanely useful. Your mileage may vary. You might like using this library. Then again, you might not. I hope you do.
Second, this is probably the most documentation that you're going to get on this. It's a really simple library and you're smart.
Thanks!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. 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. |
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (5)
Showing the top 5 NuGet packages that depend on Syrx.Validation:
Package | Downloads |
---|---|
Syrx.Commanders.Databases
This package hosts the implementation of the Syrx Database Commander which is a wrapper over Dapper's Query and Execute methods. |
|
Syrx.Commanders.Databases.Settings
This package hosts the types used by the Syrx configuration subsystem. |
|
Syrx.Commanders.Databases.Connectors
Hosts the Syrx IDatabaseConnector which is used to establish an IDbConnection to a supported RDBMS. This package also includes a base DatabaseConnector which can be used with any RDBMS that supports creating an IDbConnection through a DbProviderFactory instance. |
|
Syrx.Commanders.Databases.Settings.Extensions.Xml
This package adds support for configuration of Syrx database commands via XML file. |
|
Syrx.Commanders.Databases.Settings.Extensions.Json
This package adds support for configuration of Syrx database commands via JSON file. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Now with added delegates!