From 405fabf197762f67b65da63e6782781fccfebbb7 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 25 Sep 2019 16:49:03 +0100 Subject: [PATCH 1/3] Add async support --- Ifp.Validation/AsyncValidationRule.cs | 115 ++++++++++++++++ Ifp.Validation/AsyncValidator.cs | 174 +++++++++++++++++++++++++ Ifp.Validation/IAsyncValidationRule.cs | 30 +++++ Ifp.Validation/IAsyncValidator.cs | 21 +++ Ifp.Validation/IValidationRule.cs | 28 ++++ Ifp.Validation/Ifp.Validation.csproj | 2 + Ifp.Validation/ValidationRule.cs | 25 ---- 7 files changed, 370 insertions(+), 25 deletions(-) create mode 100644 Ifp.Validation/AsyncValidationRule.cs create mode 100644 Ifp.Validation/AsyncValidator.cs create mode 100644 Ifp.Validation/IAsyncValidationRule.cs create mode 100644 Ifp.Validation/IAsyncValidator.cs create mode 100644 Ifp.Validation/IValidationRule.cs diff --git a/Ifp.Validation/AsyncValidationRule.cs b/Ifp.Validation/AsyncValidationRule.cs new file mode 100644 index 0000000..1086f46 --- /dev/null +++ b/Ifp.Validation/AsyncValidationRule.cs @@ -0,0 +1,115 @@ +using System.Threading.Tasks; + +namespace Ifp.Validation +{ + + /// + /// The base class for implementing the validation logic. must be implemented with the validation logic. + /// + /// The type of the object to validate. + public abstract class AsyncValidationRule : IAsyncValidationRule + { + /// + /// Checks the and returns a . + /// + /// The object to validate. + /// A that represents the result of the validation. + /// + /// You can use the extension method to construct a . + /// + /// + /// Indicate success by returning . + /// + /// public override ValidationOutcome ValidateObject(Animal objectToValidate) + /// { + /// return ValidationOutcome.Success; + /// } + /// + /// + /// Return a by using the method. + /// + /// public override ValidationOutcome ValidateObject(Animal objectToValidate) + /// { + /// return ValidationOutcome.Failure(FailureSeverity.Error, "This is an error message."); + /// } + /// + /// + /// Return a using the extension method + /// . + /// + /// public override ValidationOutcome ValidateObject(Animal objectToValidate) + /// { + /// return "This is an error message.".ToFailure(FailureSeverity.Error); + /// } + /// + /// + public abstract Task ValidateObjectAsync(T objectToValidate); + + /// + /// Returns always false. Override this property and return true if + /// the should not proceed validation tests in case this validation rule returns a with . + /// This is useful to prevent further processing of rules in cases where all the following rules will also fail. A typical use case is a check for objectToValidate == null. + /// + public virtual bool CausesValidationProcessToStop => false; + } + + /// + /// The delegate defines a function that can validate another object. + /// The signature is the same as in . + /// + /// The type of the object to validate. + /// The object to validate. + /// A that represents the result of the validation. + public delegate Task AsyncValidationFunction(T objectToValidate); + + /// + /// A class that takes a delegate to perform the validation. This allows to define a validation rule without the need to implement a class that derives from . + /// + /// The type of the object to validate. + public class AsyncValidationRuleDelegate : IAsyncValidationRule + { + + /// + /// Constructs a new object and takes a delegate that does the validation. + /// + /// The delegate, that implements the validation logic. + /// + /// The property is false. + /// + public AsyncValidationRuleDelegate(AsyncValidationFunction validationFunction) + : this(validationFunction, false) + { + } + + /// + /// Constructs a new object and takes a delegate that does the validation. + /// + /// The delegate, that implements the validation logic. + /// Pass true to prevent the to proceed with more . + public AsyncValidationRuleDelegate(AsyncValidationFunction validationFunction, bool causesValidationProcessToStop) + { + ValidationFunction = validationFunction; + CausesValidationProcessToStop = causesValidationProcessToStop; + } + + /// + /// The passes to the constructor. + /// + protected AsyncValidationFunction ValidationFunction { get; } + + /// + /// Implements by delegating to the validation function passed in the constructor. + /// + /// The object to validate. + /// The . + public async Task ValidateObjectAsync(T objectToValidate) + => await ValidationFunction(objectToValidate); + + /// + /// Use the constructor to configure this property. + /// Return true if the should not proceed validation tests in case this validation rule returns a with . + /// This is useful to prevent further processing of rules in cases where all the following rules will also fail. A typical use case is a check for objectToValidate == null. + /// + public bool CausesValidationProcessToStop { get; } + } +} diff --git a/Ifp.Validation/AsyncValidator.cs b/Ifp.Validation/AsyncValidator.cs new file mode 100644 index 0000000..6a2108d --- /dev/null +++ b/Ifp.Validation/AsyncValidator.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ifp.Validation +{ + + /// + /// Base class for validators. Those validators usually don't perform validations on there own + /// but delegate the validation to one or more objects. These objects perform a single + /// isolated validation and the collects the single and wrap them in a . + /// + /// The type of the object to validate. + public abstract class AsyncValidator : IAsyncValidator + { + /// + /// Validate an object and return the objects wrapped in a . + /// + /// The object to validate. + /// The that wraps a several . + /// The can be used as a model that can be presented to the user. + /// + public abstract Task ValidateAsync(T objectToValidate); + } + + /// + /// A validator that takes a set of objects that implement the interface. + /// Use the class or the class as base for the implementation of rules. + /// + /// The type of the object to validate + public class AsyncRuleBasedValidator : AsyncValidator + { + /// + /// Constructs a validator that applies the given validation rules to an object in the given order. + /// + /// The s to apply to an object. + public AsyncRuleBasedValidator(IEnumerable> rules) : this(rules.ToArray()) { } + + /// + /// Constructs a validator that applies the given validation rules to an object in the given order. + /// + /// The s to apply to an object. + public AsyncRuleBasedValidator(params IAsyncValidationRule[] rules) + { + Rules = rules; + } + + /// + /// The rules passed in the constructor. + /// + protected IAsyncValidationRule[] Rules { get; } + + /// + /// Processes the one after the other and stops if a rule returns a + /// with and + /// both set to true. + /// + /// The object to validate. + /// A of . + protected virtual async Task> ProcessValidationsAsync(T objectToValidate) + { + var results = new List(Rules.Length); + foreach (var rule in Rules) + { + var ruleResult = await rule.ValidateObjectAsync(objectToValidate); + results.Add(ruleResult); + if (ruleResult.Severity.IsAnError && rule.CausesValidationProcessToStop) + { + break; + } + } + + return results; + } + + /// + /// Validates an object by applying the rules given in the constructor to the object in the order specified in the constructor./> + /// + /// The object to validate. + /// A that contains the of every applied . + public override async Task ValidateAsync(T objectToValidate) + => new ValidationSummary(await ProcessValidationsAsync(objectToValidate)); + } + + /// + /// An which combines the of other s. + /// + /// The type of the object to validate + public class AsyncValidatorCombiner : AsyncValidator, IAsyncValidator + { + /// + /// Constructs an that combines the of the in the given order. + /// + /// The s to combine. + public AsyncValidatorCombiner(IEnumerable> validators) : this(validators.ToArray()) + { + + } + + /// + /// Constructs an that combines the of the in the given order. + /// + /// The s to combine. + public AsyncValidatorCombiner(params IAsyncValidator[] validators) + { + Validators = validators; + } + + /// + /// The collection of validators that get combined. + /// + protected IEnumerable> Validators { get; } + + /// + /// Validates by calling of all and combining + /// their . + /// + /// The object to validate. + /// + public override async Task ValidateAsync(T objectToValidate) + { + var resultList = new List(Validators.Count()); + foreach (var validator in Validators) + { + var summary = await validator.ValidateAsync(objectToValidate); + resultList.Add(summary); + } + + return new ValidationSummary(resultList); + } + } + + /// + /// A validator, that delegates validation to another validator. This can be useful if the objectToValidate needs to be transformed before validation. + /// + /// The type to which the validation is delegated. + /// The type that this validator can validate. + public class AsyncDelegateValidator : IAsyncValidator + { + /// + /// Creates a that takes an and a from + /// to . The implements . + /// + /// An existing for . + /// An from to . + public AsyncDelegateValidator(IAsyncValidator validator, Func selector) + { + Validator = validator; + Selector = selector; + } + + /// + /// The validator to which the validation is delegated + /// + protected IAsyncValidator Validator { get; } + + /// + /// The function that transforms objectToValidate from to . + /// + protected Func Selector { get; } + + /// + /// Validates an of type by transforming it to and delegating + /// validation to . + /// + /// The object to validate. + /// A representing the result of a validation. + public async Task ValidateAsync(U objectToValidate) + { + return await Validator.ValidateAsync(Selector(objectToValidate)); + } + } +} diff --git a/Ifp.Validation/IAsyncValidationRule.cs b/Ifp.Validation/IAsyncValidationRule.cs new file mode 100644 index 0000000..a089d0e --- /dev/null +++ b/Ifp.Validation/IAsyncValidationRule.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; + +namespace Ifp.Validation +{ + /// + /// Classes that validate other objects should implement this interface. + /// Classes that implement this interface can be combined to rules sets by the . + /// + /// The type of the object to validate. + /// + /// You should not implement this interface directly. Use as base class instead. + /// + /// + /// + public interface IAsyncValidationRule + { + /// + /// Checks the and returns a . + /// + /// The object to validate. + /// A that represents the result of the validation. + Task ValidateObjectAsync(T objectToValidate); + + /// + /// Returns true if the should not proceed validation tests in case the validation returns a with . + /// This is useful to prevent further processing of rules in cases where all the following rules will also fail. A typical use case is a check for objectToValidate == null. + /// + bool CausesValidationProcessToStop { get; } + } +} diff --git a/Ifp.Validation/IAsyncValidator.cs b/Ifp.Validation/IAsyncValidator.cs new file mode 100644 index 0000000..e48d9a4 --- /dev/null +++ b/Ifp.Validation/IAsyncValidator.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; + +namespace Ifp.Validation +{ + /// + /// A validator takes an object of type and performs a validation. The result of the validation is represented by a collection + /// of wrapped in a . + /// + /// The type of the object to validate. + public interface IAsyncValidator + { + /// + /// Validate an object and return the objects wrapped in a . + /// + /// The object to validate. + /// The that wraps a several . + /// The can be used as a model that can be presented to the user. + /// + Task ValidateAsync(T objectToValidate); + } +} diff --git a/Ifp.Validation/IValidationRule.cs b/Ifp.Validation/IValidationRule.cs new file mode 100644 index 0000000..428a704 --- /dev/null +++ b/Ifp.Validation/IValidationRule.cs @@ -0,0 +1,28 @@ +namespace Ifp.Validation +{ + /// + /// Classes that validate other objects should implement this interface. + /// Classes that implement this interface can be combined to rules sets by the . + /// + /// The type of the object to validate. + /// + /// You should not implement this interface directly. Use as base class instead. + /// + /// + /// + public interface IValidationRule + { + /// + /// Checks the and returns a . + /// + /// The object to validate. + /// A that represents the result of the validation. + ValidationOutcome ValidateObject(T objectToValidate); + + /// + /// Returns true if the should not proceed validation tests in case the validation returns a with . + /// This is useful to prevent further processing of rules in cases where all the following rules will also fail. A typical use case is a check for objectToValidate == null. + /// + bool CausesValidationProcessToStop { get; } + } +} diff --git a/Ifp.Validation/Ifp.Validation.csproj b/Ifp.Validation/Ifp.Validation.csproj index 7f1ba7c..6e67b51 100644 --- a/Ifp.Validation/Ifp.Validation.csproj +++ b/Ifp.Validation/Ifp.Validation.csproj @@ -42,10 +42,12 @@ + + diff --git a/Ifp.Validation/ValidationRule.cs b/Ifp.Validation/ValidationRule.cs index 35bc882..6b05cdc 100644 --- a/Ifp.Validation/ValidationRule.cs +++ b/Ifp.Validation/ValidationRule.cs @@ -1,30 +1,5 @@ namespace Ifp.Validation { - /// - /// Classes that validate other objects should implement this interface. - /// Classes that implement this interface can be combined to rules sets by the . - /// - /// The type of the object to validate. - /// - /// You should not implement this interface directly. Use as base class instead. - /// - /// - /// - public interface IValidationRule - { - /// - /// Checks the and returns a . - /// - /// The object to validate. - /// A that represents the result of the validation. - ValidationOutcome ValidateObject(T objectToValidate); - - /// - /// Returns true if the should not proceed validation tests in case the validation returns a with . - /// This is useful to prevent further processing of rules in cases where all the following rules will also fail. A typical use case is a check for objectToValidate == null. - /// - bool CausesValidationProcessToStop { get; } - } /// /// The base class for implementing the validation logic. must be implemented with the validation logic. From e2ed9b41a4310e9b4590c867b3d1a5400ca5891a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 25 Sep 2019 16:56:46 +0100 Subject: [PATCH 2/3] Update nuget package properties --- Ifp.Validation/Ifp.Validation.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ifp.Validation/Ifp.Validation.csproj b/Ifp.Validation/Ifp.Validation.csproj index 6e67b51..ce199df 100644 --- a/Ifp.Validation/Ifp.Validation.csproj +++ b/Ifp.Validation/Ifp.Validation.csproj @@ -16,13 +16,13 @@ true snupkg validation;valid;input;dependency injection;testable;extensible;rules;rules engine - New in version 1.5: Added DelegateValidator<T, U> + New in version 1.5: Added Async support https://cdn1.iconfinder.com/data/icons/material-core/20/check-circle-outline-32.png https://github.com/ifpanalytics/Ifp.Validation MIT git https://github.com/ifpanalytics/Ifp.Validation - 1.5.0 + 1.6.0 true From ebee2c2ff7d544b8ff51826005a0f97d48a7093c Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 25 Sep 2019 16:57:41 +0100 Subject: [PATCH 3/3] Fix type in csproj --- Ifp.Validation/Ifp.Validation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ifp.Validation/Ifp.Validation.csproj b/Ifp.Validation/Ifp.Validation.csproj index ce199df..809fd01 100644 --- a/Ifp.Validation/Ifp.Validation.csproj +++ b/Ifp.Validation/Ifp.Validation.csproj @@ -16,7 +16,7 @@ true snupkg validation;valid;input;dependency injection;testable;extensible;rules;rules engine - New in version 1.5: Added Async support + New in version 1.6: Added Async support https://cdn1.iconfinder.com/data/icons/material-core/20/check-circle-outline-32.png https://github.com/ifpanalytics/Ifp.Validation MIT