diff --git a/CHANGELOG.md b/CHANGELOG.md index aba75576..e413a20d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Represents the **NuGet** versions. +## v3.7.0 +- *Enhancement:* The `Mapper` has a new constructor override to enable the specification of the mapping (`OnMap` equivalent) logic. +- *Enhancement:* The `Mapper` has had `When*` helper methods added to aid the specification of the mapping logic depending on the `OperationTypes` (singular) being performed. +- *Enhancement:* A new `NoneRule` validation has been added to ensure that a value is none (i.e. must be its default value). + ## v3.6.3 - *Fixed:* All related package dependencies updated to latest. diff --git a/Common.targets b/Common.targets index abf22760..84086f50 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@  - 3.6.3 + 3.7.0 preview Avanade Avanade diff --git a/src/CoreEx.Validation/Resources.resx b/src/CoreEx.Validation/Resources.resx index a9c6fdf4..365a71c9 100644 --- a/src/CoreEx.Validation/Resources.resx +++ b/src/CoreEx.Validation/Resources.resx @@ -234,6 +234,9 @@ {0} is invalid. + + {0} must not be specified. + Requested data was not found. diff --git a/src/CoreEx.Validation/Rules/NoneRule.cs b/src/CoreEx.Validation/Rules/NoneRule.cs new file mode 100644 index 00000000..3bd0e85c --- /dev/null +++ b/src/CoreEx.Validation/Rules/NoneRule.cs @@ -0,0 +1,37 @@ +// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CoreEx.Validation.Rules +{ + /// + /// Provides validation to ensure the value is not specified (is none); determined as when it does not equal its default value. + /// + /// The entity . + /// The property . + /// A value will be determined as none when it equals its default value. For example an will trigger when the value is zero; however, a + /// will trigger when null only (a zero is considered a value in this instance). + public class NoneRule : ValueRuleBase where TEntity : class + { + /// + protected override Task ValidateAsync(PropertyContext context, CancellationToken cancellationToken = default) + { + // Compare the value against its default. + if (Comparer.Default.Compare(context.Value, default!) != 0) + { + CreateErrorMessage(context); + return Task.CompletedTask; + } + + return Task.CompletedTask; + } + + /// + /// Create the error message. + /// + private void CreateErrorMessage(PropertyContext context) => context.CreateErrorMessage(ErrorText ?? ValidatorStrings.NoneFormat); + } +} \ No newline at end of file diff --git a/src/CoreEx.Validation/ValidationExtensions.cs b/src/CoreEx.Validation/ValidationExtensions.cs index 53dd1e10..87395573 100644 --- a/src/CoreEx.Validation/ValidationExtensions.cs +++ b/src/CoreEx.Validation/ValidationExtensions.cs @@ -17,6 +17,7 @@ using System.Threading.Tasks; using static System.Net.Mime.MediaTypeNames; using System.Xml.Linq; +using System.Data; namespace CoreEx.Validation { @@ -37,7 +38,7 @@ public static class ValidationExtensions /// A . public static IPropertyRule Text(this IPropertyRule rule, LText text) where TEntity : class { - (rule ?? throw new ArgumentNullException(nameof(rule))).Text = text; + rule.ThrowIfNull(nameof(rule)).Text = text; return rule; } @@ -56,7 +57,7 @@ public static IPropertyRule When(this IP if (predicate == null) return rule; - (rule ?? throw new ArgumentNullException(nameof(rule))).AddClause(new WhenClause(predicate)); + rule.ThrowIfNull(nameof(rule)).AddClause(new WhenClause(predicate)); return rule; } @@ -71,7 +72,7 @@ public static IPropertyRule WhenValue(th if (predicate == null) return rule; - (rule ?? throw new ArgumentNullException(nameof(rule))).AddClause(new WhenClause(predicate)); + rule.ThrowIfNull(nameof(rule)).AddClause(new WhenClause(predicate)); return rule; } @@ -94,7 +95,7 @@ public static IPropertyRule When(this IP if (when == null) return rule; - (rule ?? throw new ArgumentNullException(nameof(rule))).AddClause(new WhenClause(when)); + rule.ThrowIfNull(nameof(rule)).AddClause(new WhenClause(when)); return rule; } @@ -142,7 +143,22 @@ public static IPropertyRule WhenNotOperationThe error message format text (overrides the default). /// A . public static IPropertyRule Mandatory(this IPropertyRule rule, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new MandatoryRule { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new MandatoryRule { ErrorText = errorText }); + + #endregion + + #region None + + /// + /// Adds a none validation () where it is expected that the value equals its default. + /// + /// The entity . + /// The property . + /// The being extended. + /// The error message format text (overrides the default). + /// A . + public static IPropertyRule None(this IPropertyRule rule, LText? errorText = null) where TEntity : class + => rule.ThrowIfNull(nameof(rule)).AddRule(new NoneRule { ErrorText = errorText }); #endregion @@ -158,7 +174,7 @@ public static IPropertyRule Mandatory(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Must(this IPropertyRule rule, Predicate predicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new MustRule(predicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new MustRule(predicate) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return true to be considered valid (see ). @@ -170,7 +186,7 @@ public static IPropertyRule Must(this IP /// The error message format text (overrides the default). /// A . public static IPropertyRule Must(this IPropertyRule rule, Func must, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new MustRule(must) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new MustRule(must) { ErrorText = errorText }); /// /// Adds a validation where the rule value be true to be considered valid (see ). @@ -182,7 +198,7 @@ public static IPropertyRule Must(this IP /// The error message format text (overrides the default). /// A . public static IPropertyRule Must(this IPropertyRule rule, bool must, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new MustRule(() => must) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new MustRule(() => must) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return true to be considered valid (see ). @@ -194,7 +210,7 @@ public static IPropertyRule Must(this IP /// The error message format text (overrides the default). /// A . public static IPropertyRule MustAsync(this IPropertyRule rule, Func> mustAsync, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new MustRule(mustAsync) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new MustRule(mustAsync) { ErrorText = errorText }); #endregion @@ -210,7 +226,7 @@ public static IPropertyRule MustAsync(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Exists(this IPropertyRule rule, Predicate predicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule(predicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule(predicate) { ErrorText = errorText }); /// /// Adds a validation where the rule function exists return true to verify it exists (see ). @@ -222,7 +238,7 @@ public static IPropertyRule Exists(this /// The error message format text (overrides the default). /// A . public static IPropertyRule ExistsAsync(this IPropertyRule rule, Func> exists, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule(exists) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule(exists) { ErrorText = errorText }); /// /// Adds a validation where the rule value is true to verify it exists (see ). @@ -234,7 +250,7 @@ public static IPropertyRule ExistsAsync( /// The error message format text (overrides the default). /// A . public static IPropertyRule Exists(this IPropertyRule rule, bool exists, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule((_, __) => Task.FromResult(exists)) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule((_, __) => Task.FromResult(exists)) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return not null to verify it exists (see ). @@ -246,7 +262,7 @@ public static IPropertyRule Exists(this /// The error message format text (overrides the default). /// A . public static IPropertyRule ExistsAsync(this IPropertyRule rule, Func> exists, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule(exists) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule(exists) { ErrorText = errorText }); /// /// Adds a validation where the rule is not null to verify it exists (see ). @@ -258,7 +274,7 @@ public static IPropertyRule ExistsAsync( /// The error message format text (overrides the default). /// A . public static IPropertyRule Exists(this IPropertyRule rule, object? exists, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule((_, __) => Task.FromResult(exists != null)) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule((_, __) => Task.FromResult(exists != null)) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return a successful response to verify it exists (see ). @@ -270,7 +286,7 @@ public static IPropertyRule Exists(this /// The error message format text (overrides the default). /// A . public static IPropertyRule AgentExistsAsync(this IPropertyRule rule, Func> agentResult, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule(async (v, ct) => await agentResult(v, ct).ConfigureAwait(false)) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule(async (v, ct) => await agentResult(v, ct).ConfigureAwait(false)) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return a successful response to verify it exists (see ). @@ -283,7 +299,7 @@ public static IPropertyRule AgentExistsAsyncThe error message format text (overrides the default). /// A . public static IPropertyRule AgentExistsAsync(this IPropertyRule rule, Func>> agentResult, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ExistsRule(async (v, ct) => await agentResult(v, ct).ConfigureAwait(false)) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ExistsRule(async (v, ct) => await agentResult(v, ct).ConfigureAwait(false)) { ErrorText = errorText }); #endregion @@ -299,7 +315,7 @@ public static IPropertyRule AgentExistsAsyncThe error message format text (overrides the default). /// A . public static IPropertyRule Duplicate(this IPropertyRule rule, Predicate predicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DuplicateRule(predicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DuplicateRule(predicate) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return false to not be considered a duplicate (see ). @@ -311,7 +327,7 @@ public static IPropertyRule Duplicate(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Duplicate(this IPropertyRule rule, Func duplicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DuplicateRule(duplicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DuplicateRule(duplicate) { ErrorText = errorText }); /// /// Adds a validation where the rule value must be false to not be considered a duplicate (see ). @@ -323,7 +339,7 @@ public static IPropertyRule Duplicate(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Duplicate(this IPropertyRule rule, bool duplicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DuplicateRule(() => duplicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DuplicateRule(() => duplicate) { ErrorText = errorText }); /// /// Adds a validation where considered a duplicate (see ). @@ -334,7 +350,7 @@ public static IPropertyRule Duplicate(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Duplicate(this IPropertyRule rule, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DuplicateRule(() => true) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DuplicateRule(() => true) { ErrorText = errorText }); #endregion @@ -350,7 +366,7 @@ public static IPropertyRule Duplicate(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Immutable(this IPropertyRule rule, Predicate predicate, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ImmutableRule(predicate) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ImmutableRule(predicate) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return true to be considered valid (see ). @@ -362,7 +378,7 @@ public static IPropertyRule Immutable(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Immutable(this IPropertyRule rule, Func immutable, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ImmutableRule(immutable) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ImmutableRule(immutable) { ErrorText = errorText }); /// /// Adds a validation where the rule function must return true to be considered valid (see ). @@ -374,7 +390,7 @@ public static IPropertyRule Immutable(th /// The error message format text (overrides the default). /// A . public static IPropertyRule ImmutableAsync(this IPropertyRule rule, Func> immutableAsync, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ImmutableRule(immutableAsync) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ImmutableRule(immutableAsync) { ErrorText = errorText }); /// /// Adds a validation where the rule value be true to be considered valid (see ). @@ -386,7 +402,7 @@ public static IPropertyRule ImmutableAsyncThe error message format text (overrides the default). /// A . public static IPropertyRule Immutable(this IPropertyRule rule, bool immutable, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ImmutableRule(() => immutable) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ImmutableRule(() => immutable) { ErrorText = errorText }); /// /// Adds a validation where considered immutable (see ). @@ -397,7 +413,7 @@ public static IPropertyRule Immutable(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Immutable(this IPropertyRule rule, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ImmutableRule(() => false) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ImmutableRule(() => false) { ErrorText = errorText }); #endregion @@ -417,7 +433,7 @@ public static IPropertyRule Immutable(th /// The error message format text (overrides the default). /// A . public static IPropertyRule Between(this IPropertyRule rule, TProperty compareFromValue, TProperty compareToValue, LText? compareFromText = null, LText? compareToText = null, bool exclusiveBetween = false, LText ? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new BetweenRule(compareFromValue, compareToValue, compareFromText, compareToText, exclusiveBetween) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new BetweenRule(compareFromValue, compareToValue, compareFromText, compareToText, exclusiveBetween) { ErrorText = errorText }); /// /// Adds a between comparision validation against from and to values returned by functions (). @@ -433,7 +449,7 @@ public static IPropertyRule Between(this /// The error message format text (overrides the default). /// A . public static IPropertyRule Between(this IPropertyRule rule, Func compareFromValueFunction, Func compareToValueFunction, Func? compareFromTextFunction = null, Func? compareToTextFunction = null, bool exclusiveBetween = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new BetweenRule(compareFromValueFunction, compareToValueFunction, compareFromTextFunction, compareToTextFunction, exclusiveBetween) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new BetweenRule(compareFromValueFunction, compareToValueFunction, compareFromTextFunction, compareToTextFunction, exclusiveBetween) { ErrorText = errorText }); /// /// Adds a between comparision validation against from and to values returned by async functions (). @@ -449,7 +465,7 @@ public static IPropertyRule Between(this /// The error message format text (overrides the default). /// A . public static IPropertyRule BetweenAsync(this IPropertyRule rule, Func> compareFromValueFunctionAsync, Func> compareToValueFunctionAsync, Func? compareFromTextFunction = null, Func? compareToTextFunction = null, bool exclusiveBetween = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new BetweenRule(compareFromValueFunctionAsync, compareToValueFunctionAsync, compareFromTextFunction, compareToTextFunction, exclusiveBetween) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new BetweenRule(compareFromValueFunctionAsync, compareToValueFunctionAsync, compareFromTextFunction, compareToTextFunction, exclusiveBetween) { ErrorText = errorText }); #endregion @@ -467,7 +483,7 @@ public static IPropertyRule BetweenAsync /// The error message format text (overrides the default). /// A . public static IPropertyRule CompareValue(this IPropertyRule rule, CompareOperator compareOperator, TProperty compareToValue, LText? compareToText = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValueRule(compareOperator, compareToValue, compareToText) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValueRule(compareOperator, compareToValue, compareToText) { ErrorText = errorText }); /// /// Adds a comparision validation against a value returned by a function (). @@ -481,7 +497,7 @@ public static IPropertyRule CompareValue /// The error message format text (overrides the default). /// A . public static IPropertyRule CompareValue(this IPropertyRule rule, CompareOperator compareOperator, Func compareToValueFunction, Func? compareToTextFunction = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValueRule(compareOperator, compareToValueFunction, compareToTextFunction) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValueRule(compareOperator, compareToValueFunction, compareToTextFunction) { ErrorText = errorText }); /// /// Adds a comparision validation against a value returned by an async function (). @@ -495,7 +511,7 @@ public static IPropertyRule CompareValue /// The error message format text (overrides the default). /// A . public static IPropertyRule CompareValueAsync(this IPropertyRule rule, CompareOperator compareOperator, Func> compareToValueFunctionAsync, Func? compareToTextFunction = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValueRule(compareOperator, compareToValueFunctionAsync, compareToTextFunction) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValueRule(compareOperator, compareToValueFunctionAsync, compareToTextFunction) { ErrorText = errorText }); /// /// Adds a comparision validation against one or more specified values (see ). @@ -507,7 +523,7 @@ public static IPropertyRule CompareValueAsyncThe error message format text (overrides the default). /// A . public static IPropertyRule CompareValues(this IPropertyRule rule, IEnumerable compareToValues, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValuesRule(compareToValues) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValuesRule(compareToValues) { ErrorText = errorText }); /// /// Adds a comparision validation against one or more specified values (see ). @@ -519,7 +535,7 @@ public static IPropertyRule CompareValuesThe error message format text (overrides the default). /// A . public static IPropertyRule CompareValues(this IPropertyRule rule, Func>> compareToValuesFunctionAsync, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValuesRule(compareToValuesFunctionAsync) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValuesRule(compareToValuesFunctionAsync) { ErrorText = errorText }); /// /// Adds a comparision validation against one or more specified values (see ). @@ -532,7 +548,7 @@ public static IPropertyRule CompareValuesThe error message format text (overrides the default). /// A . public static IPropertyRule CompareValues(this IPropertyRule rule, IEnumerable compareToValues, bool ignoreCase, bool overrideValue = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CompareValuesRule(compareToValues) { EqualityComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal, OverrideValue = overrideValue, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CompareValuesRule(compareToValues) { EqualityComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal, OverrideValue = overrideValue, ErrorText = errorText }); #endregion @@ -551,7 +567,7 @@ public static IPropertyRule CompareValues(this IProper /// The error message format text (overrides the default). /// A . public static IPropertyRule CompareProperty(this IPropertyRule rule, CompareOperator compareOperator, Expression> compareToPropertyExpression, LText? compareToText = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ComparePropertyRule(compareOperator, compareToPropertyExpression, compareToText) { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ComparePropertyRule(compareOperator, compareToPropertyExpression, compareToText) { ErrorText = errorText }); #endregion @@ -567,7 +583,7 @@ public static IPropertyRule ComparePropertyThe error message format text (overrides the default). /// A . public static IPropertyRule String(this IPropertyRule rule, int maxLength, Regex? regex = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new StringRule { MaxLength = maxLength, Regex = regex, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new StringRule { MaxLength = maxLength, Regex = regex, ErrorText = errorText }); /// /// Adds a validation with a minimum and maximum length (see ). @@ -580,7 +596,7 @@ public static IPropertyRule String(this IPropertyRule< /// The error message format text (overrides the default). /// A . public static IPropertyRule String(this IPropertyRule rule, int minLength, int? maxLength, Regex? regex = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new StringRule { MinLength = minLength, MaxLength = maxLength, Regex = regex, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new StringRule { MinLength = minLength, MaxLength = maxLength, Regex = regex, ErrorText = errorText }); /// /// Adds a validation with a (see ). @@ -591,7 +607,7 @@ public static IPropertyRule String(this IPropertyRule< /// The error message format text (overrides the default). /// A . public static IPropertyRule String(this IPropertyRule rule, Regex? regex = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new StringRule { Regex = regex, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new StringRule { Regex = regex, ErrorText = errorText }); #endregion @@ -608,7 +624,7 @@ public static IPropertyRule String(this IPropertyRule< /// The maximum length for an email address is '254' as per this article, /// hence the default. public static IPropertyRule Email(this IPropertyRule rule, int? maxLength = 254, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new EmailRule { MaxLength = maxLength, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new EmailRule { MaxLength = maxLength, ErrorText = errorText }); #endregion @@ -623,7 +639,7 @@ public static IPropertyRule Email(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Enum(this IPropertyRule rule, LText? errorText = null) where TEntity : class where TProperty : struct, Enum - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new EnumRule { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new EnumRule { ErrorText = errorText }); /// /// Adds an validation to ensure that the value has been defined (see ). @@ -634,7 +650,7 @@ public static IPropertyRule Enum(this IP /// The error message format text (overrides the default). /// A . public static IPropertyRule Enum(this IPropertyRule rule, LText? errorText = null) where TEntity : class where TProperty : struct, Enum - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new NullableEnumRule { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new NullableEnumRule { ErrorText = errorText }); /// /// Enables the addition of an using an to validate against a specified . @@ -643,7 +659,7 @@ public static IPropertyRule Enum(this IP /// The being extended. /// A . public static EnumValueRuleAs Enum(this IPropertyRule rule) where TEntity : class - => new(rule ?? throw new ArgumentNullException(nameof(rule))) { }; + => new(rule.ThrowIfNull(nameof(rule))) { }; #endregion @@ -658,7 +674,7 @@ public static EnumValueRuleAs Enum(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Wildcard(this IPropertyRule rule, Wildcard? wildcard = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new WildcardRule { Wildcard = wildcard, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new WildcardRule { Wildcard = wildcard, ErrorText = errorText }); #endregion @@ -674,7 +690,7 @@ public static IPropertyRule Wildcard(this IPropertyRul /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -686,7 +702,7 @@ public static IPropertyRule Numeric(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); /// /// Adds a validation (see ); @@ -698,7 +714,7 @@ public static IPropertyRule Numeric(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -710,7 +726,7 @@ public static IPropertyRule Numeric(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -723,7 +739,7 @@ public static IPropertyRule Numeric(this IPropertyRuleThe error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, int? decimalPlaces = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, DecimalPlaces = decimalPlaces, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, DecimalPlaces = decimalPlaces, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -736,7 +752,7 @@ public static IPropertyRule Numeric(this IPropertyRul /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, int? decimalPlaces = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, DecimalPlaces = decimalPlaces, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, DecimalPlaces = decimalPlaces, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -747,7 +763,7 @@ public static IPropertyRule Numeric(this IPropertyRul /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -758,7 +774,7 @@ public static IPropertyRule Numeric(this IPropertyRule< /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -769,7 +785,7 @@ public static IPropertyRule Numeric(this IPropertyRule< /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); /// /// Adds a validation (see ). @@ -780,7 +796,7 @@ public static IPropertyRule Numeric(this IPropertyRule /// The error message format text (overrides the default). /// A . public static IPropertyRule Numeric(this IPropertyRule rule, bool allowNegatives = false, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new NumericRule { AllowNegatives = allowNegatives, ErrorText = errorText }); #endregion @@ -798,7 +814,7 @@ public static IPropertyRule Numeric(this IPropertyRule /// The error message format text (overrides the default). /// A . public static IPropertyRule Currency(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, NumberFormatInfo? currencyFormatInfo = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, @@ -818,7 +834,7 @@ public static IPropertyRule Currency(this IPropertyRu /// The error message format text (overrides the default). /// A . public static IPropertyRule Currency(this IPropertyRule rule, bool allowNegatives = false, int? maxDigits = null, NumberFormatInfo? currencyFormatInfo = null, LText? errorText = null) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new DecimalRule + => rule.ThrowIfNull(nameof(rule)).AddRule(new DecimalRule { AllowNegatives = allowNegatives, MaxDigits = maxDigits, @@ -839,7 +855,7 @@ public static IPropertyRule Currency(this IPropertyRu /// The error message format text (overrides the default). /// A . public static IPropertyRule IsValid(this IPropertyRule rule, LText? errorText = null) where TEntity : class where TProperty : IReferenceData? - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ReferenceDataRule { ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ReferenceDataRule { ErrorText = errorText }); /// /// Adds a validation (see ) to ensure the list of SIDs are valid. @@ -853,7 +869,7 @@ public static IPropertyRule IsValid(this /// The error message format text (overrides the default). /// A . public static IPropertyRule AreValid(this IPropertyRule rule, bool allowDuplicates = false, int minCount = 0, int? maxCount = null, LText? errorText = null) where TEntity : class where TProperty : IReferenceDataCodeList - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new ReferenceDataSidListRule { AllowDuplicates = allowDuplicates, MinCount = minCount, MaxCount = maxCount, ErrorText = errorText }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new ReferenceDataSidListRule { AllowDuplicates = allowDuplicates, MinCount = minCount, MaxCount = maxCount, ErrorText = errorText }); /// /// Adds a validation (see to ensure the Code is valid. @@ -883,7 +899,7 @@ public static ReferenceDataCodeRuleAs RefDataCode(this IProper public static IPropertyRule Collection(this IPropertyRule rule, int minCount = 0, int? maxCount = null, ICollectionRuleItem? item = null, bool allowNullItems = false) where TEntity : class where TProperty : System.Collections.IEnumerable? { var cr = new CollectionRule { MinCount = minCount, MaxCount = maxCount, Item = item, AllowNullItems = allowNullItems }; - return (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(cr); + return rule.ThrowIfNull(nameof(rule)).AddRule(cr); } #endregion @@ -905,7 +921,7 @@ public static IPropertyRule Collection(t public static IPropertyRule Dictionary(this IPropertyRule rule, int minCount = 0, int? maxCount = null, IDictionaryRuleItem? item = null, bool allowNullKeys = false, bool allowNullValues = false) where TEntity : class where TProperty : System.Collections.IDictionary? { var cr = new DictionaryRule { MinCount = minCount, MaxCount = maxCount, Item = item, AllowNullKeys = allowNullKeys, AllowNullValues = allowNullValues }; - return (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(cr); + return rule.ThrowIfNull(nameof(rule)).AddRule(cr); } #endregion @@ -922,7 +938,7 @@ public static IPropertyRule Dictionary(t /// The validator. /// A . public static IPropertyRule Entity(this IPropertyRule rule, TValidator validator) where TEntity : class where TProperty : class? where TValidator : IValidatorEx - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new EntityRule(validator)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new EntityRule(validator)); /// /// Enables the addition of an using a validator a specified validator . @@ -932,7 +948,7 @@ public static IPropertyRule EntityThe being extended. /// An . public static EntityRuleWith Entity(this IPropertyRule rule) where TEntity : class where TProperty : class? - => new(rule ?? throw new ArgumentNullException(nameof(rule))); + => new(rule.ThrowIfNull(nameof(rule))); #endregion @@ -949,7 +965,7 @@ public static EntityRuleWith Entity(this /// A . /// This is only intended to be leveraged for the root entity value being validated as no are passed meaning advanced capabilities will be ignored. public static IPropertyRule Interop(this IPropertyRule rule, TValidator validator) where TEntity : class where TProperty : class? where TValidator : IValidator - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new InteropRule(() => validator ?? throw new ArgumentNullException(nameof(validator)))); + => rule.ThrowIfNull(nameof(rule)).AddRule(new InteropRule(() => validator ?? throw new ArgumentNullException(nameof(validator)))); /// /// Adds an interop validation (see ) (intended for non-CoreEx.Validation). @@ -962,7 +978,7 @@ public static IPropertyRule InteropA . /// This is only intended to be leveraged for the root entity value being validated as no are passed meaning advanced capabilities will be ignored. public static IPropertyRule Interop(this IPropertyRule rule, Func validatorFunc) where TEntity : class where TProperty : class? where TValidator : IValidator - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new InteropRule(validatorFunc)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new InteropRule(validatorFunc)); #endregion @@ -977,7 +993,7 @@ public static IPropertyRule InteropThe custom function. /// A . public static IPropertyRule Custom(this IPropertyRule rule, Func, Result> custom) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CustomRule(custom)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CustomRule(custom)); /// /// Adds a validation (see ). @@ -988,7 +1004,7 @@ public static IPropertyRule Custom(this /// The custom function. /// A . public static IPropertyRule CustomAsync(this IPropertyRule rule, Func, CancellationToken, Task> customAsync) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CustomRule(customAsync)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CustomRule(customAsync)); #endregion @@ -1003,7 +1019,7 @@ public static IPropertyRule CustomAsync( /// The . /// A . public static IPropertyRule Common(this IPropertyRule rule, CommonValidator validator) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new CommonRule(validator)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new CommonRule(validator)); #endregion @@ -1018,7 +1034,7 @@ public static IPropertyRule Common(this /// The override function. /// A . public static IPropertyRule Override(this IPropertyRule rule, Func overrideFunc) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(overrideFunc)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(overrideFunc)); /// /// Adds a value override (see ) using the specified . @@ -1029,7 +1045,7 @@ public static IPropertyRule Override(thi /// The override function. /// A . public static IPropertyRule OverrideAsync(this IPropertyRule rule, Func> overrideFuncAsync) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(overrideFuncAsync)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(overrideFuncAsync)); /// /// Adds a value override (see ) using the specified . @@ -1040,7 +1056,7 @@ public static IPropertyRule OverrideAsyncThe override value. /// A . public static IPropertyRule Override(this IPropertyRule rule, TProperty overrideValue) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(overrideValue)); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(overrideValue)); /// /// Adds a default (see ) using the specified (overrides only where current value is the default for ) . @@ -1051,7 +1067,7 @@ public static IPropertyRule Override(thi /// The override function. /// A . public static IPropertyRule Default(this IPropertyRule rule, Func defaultFunc) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(defaultFunc) { OnlyOverrideDefault = true }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(defaultFunc) { OnlyOverrideDefault = true }); /// /// Adds a default (see ) using the specified (overrides only where current value is the default for ) . @@ -1062,7 +1078,7 @@ public static IPropertyRule Default(this /// The override function. /// A . public static IPropertyRule DefaultAsync(this IPropertyRule rule, Func> defaultFuncAsync) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(defaultFuncAsync) { OnlyOverrideDefault = true }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(defaultFuncAsync) { OnlyOverrideDefault = true }); /// /// Adds a default override (see ) using the specified (overrides only where current value is the default for ) . @@ -1073,7 +1089,7 @@ public static IPropertyRule DefaultAsync /// The override value. /// A . public static IPropertyRule Default(this IPropertyRule rule, TProperty defaultValue) where TEntity : class - => (rule ?? throw new ArgumentNullException(nameof(rule))).AddRule(new OverrideRule(defaultValue) { OnlyOverrideDefault = true }); + => rule.ThrowIfNull(nameof(rule)).AddRule(new OverrideRule(defaultValue) { OnlyOverrideDefault = true }); #endregion diff --git a/src/CoreEx.Validation/ValidatorStrings.cs b/src/CoreEx.Validation/ValidatorStrings.cs index 4cd59f51..1cde62a1 100644 --- a/src/CoreEx.Validation/ValidatorStrings.cs +++ b/src/CoreEx.Validation/ValidatorStrings.cs @@ -190,6 +190,12 @@ public static class ValidatorStrings /// Defaults to: '{0} is an invalid e-mail address'. public static LText EmailFormat { get; set; } = new("CoreEx.Validation.EmailFormat"); + /// + /// Gets or sets the format string for when no (none) value is to be specified. + /// + /// Defaults to: '{0} must not be specified.'. + public static LText NoneFormat { get; set; } = new("CoreEx.Validation.NoneFormat"); + /// /// Gets or sets the string for the literal. /// diff --git a/src/CoreEx/Http/HttpRequestLogger.cs b/src/CoreEx/Http/HttpRequestLogger.cs index ab530318..b5f7160c 100644 --- a/src/CoreEx/Http/HttpRequestLogger.cs +++ b/src/CoreEx/Http/HttpRequestLogger.cs @@ -114,7 +114,7 @@ public async Task LogResponseAsync(HttpRequestMessage request, HttpResponseMessa } else { - _logger.LogError("Unexpected HTTP Response in {Time} {HttpRequestHost} {HttpStatusCodeText} ({HttpStatusCode})", + _logger.LogDebug("Unsuccessful HTTP Response in {Time} {HttpRequestHost} {HttpStatusCodeText} ({HttpStatusCode})", operationTime, request.RequestUri?.Host, response.StatusCode, diff --git a/src/CoreEx/Mapping/Mapper.cs b/src/CoreEx/Mapping/Mapper.cs index 4347b466..ad2e5f1d 100644 --- a/src/CoreEx/Mapping/Mapper.cs +++ b/src/CoreEx/Mapping/Mapper.cs @@ -199,5 +199,63 @@ internal EmptyMapper() { } [return: NotNullIfNotNull(nameof(source))] public TDestination? Map(TSource? source, TDestination? destination, OperationTypes operationType = OperationTypes.Unspecified) => throw new NotImplementedException(); } + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenGet(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.Get, operationType, action); + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenCreate(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.Create, operationType, action); + + /// + /// When is an then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenUpdate(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.Update, operationType, action); + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenDelete(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.Delete, operationType, action); + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenAnyExceptGet(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.AnyExceptGet, operationType, action); + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenAnyExceptCreate(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.AnyExceptCreate, operationType, action); + + /// + /// When is a then the action is invoked. + /// + /// The singular . + /// The action to invoke. + public static void WhenAnyExceptUpdate(OperationTypes operationType, Action action) => WhenOperationType(OperationTypes.AnyExceptUpdate, operationType, action); + + /// + /// When the matches the then the is invoked. + /// + private static void WhenOperationType(OperationTypes expectedOperationTypes, OperationTypes operationType, Action action) + { + if (expectedOperationTypes.HasFlag(operationType)) + action?.Invoke(); + } } } \ No newline at end of file diff --git a/src/CoreEx/Mapping/MapperT.cs b/src/CoreEx/Mapping/MapperT.cs index 1fa7447d..5c0992ff 100644 --- a/src/CoreEx/Mapping/MapperT.cs +++ b/src/CoreEx/Mapping/MapperT.cs @@ -14,10 +14,23 @@ namespace CoreEx.Mapping public class Mapper : IMapper where TSource : class, new() where TDestination : class, new() { private readonly List<(Action action, OperationTypes types, Func? isSourceInitial, Action? initializeDestination)> _mappings = []; + private readonly Func? _onMap; private Mapper? _mapper; private Func? _isSourceInitial; private Func? _initializeDestination; + /// + /// Initializes a new instance of the class. + /// + public Mapper() { } + + /// + /// Initializes a new instance of the class with an function. + /// + /// The mapping function. + /// Provides a simple means to create an instance with logic specified within the constructor; versus, having to inherit to implement. + public Mapper(Func onMap) => _onMap = onMap.ThrowIfNull(nameof(onMap)); + /// public Mapper Owner { @@ -260,15 +273,15 @@ public Mapper InitializeDestination(FuncThe source. /// The destination. /// The singular . - internal virtual TDestination? Map(TSource? source, TDestination? destination, OperationTypes operationType) + public virtual TDestination? Map(TSource? source, TDestination? destination, OperationTypes operationType) { if (source is null && destination is null) - return OnMap(source, destination, operationType); + return OnMapInternal(source, destination, operationType); if (source is null && destination is not null) { destination = default; - return OnMap(source, destination, operationType); + return OnMapInternal(source, destination, operationType); } if (destination is not null) @@ -280,6 +293,14 @@ public Mapper InitializeDestination(Func((s, d, t) => + { + d ??= new PersonB(); + Mapper.WhenCreate(t, () => d!.ID = s?.Id ?? 0); + return d; + }); + + var d = m.Map(new PersonA { Id = 88, Name = "blah" }, null, OperationTypes.Create); + Assert.AreEqual(88, d!.ID); + + d = m.Map(new PersonA { Id = 88, Name = "blah" }, null, OperationTypes.Update); + Assert.AreEqual(0, d!.ID); + } + public class PersonAMapper : Mapper { public PersonAMapper() diff --git a/tests/CoreEx.Test/Framework/Validation/Rules/NoneRuleTest.cs b/tests/CoreEx.Test/Framework/Validation/Rules/NoneRuleTest.cs new file mode 100644 index 00000000..f7ea36e7 --- /dev/null +++ b/tests/CoreEx.Test/Framework/Validation/Rules/NoneRuleTest.cs @@ -0,0 +1,75 @@ +using NUnit.Framework; +using CoreEx.Validation; +using CoreEx.Entities; +using System.Threading.Tasks; + +namespace CoreEx.Test.Framework.Validation.Rules +{ + [TestFixture] + public class NoneRuleTest + { + [OneTimeSetUp] + public void OneTimeSetUp() => CoreEx.Localization.TextProvider.SetTextProvider(new ValidationTextProvider()); + + [Test] + public async Task Validate_String() + { + var v1 = await "XXX".Validate("value").None().ValidateAsync(); + Assert.IsTrue(v1.HasErrors); + Assert.AreEqual(1, v1.Messages!.Count); + Assert.AreEqual("Value must not be specified.", v1.Messages[0].Text); + Assert.AreEqual(MessageType.Error, v1.Messages[0].Type); + Assert.AreEqual("value", v1.Messages[0].Property); + + v1 = await ((string?)null).Validate("value").None().ValidateAsync(); + Assert.IsFalse(v1.HasErrors); + + v1 = await (string.Empty).Validate("value").None().ValidateAsync(); + Assert.IsTrue(v1.HasErrors); + } + + [Test] + public async Task Validate_Int32() + { + var v1 = await (123).Validate("value").None().ValidateAsync(); + Assert.IsTrue(v1.HasErrors); + Assert.AreEqual(1, v1.Messages!.Count); + Assert.AreEqual("Value must not be specified.", v1.Messages[0].Text); + Assert.AreEqual(MessageType.Error, v1.Messages[0].Type); + Assert.AreEqual("value", v1.Messages[0].Property); + + v1 = await (0).Validate("value").None().ValidateAsync(); + Assert.IsFalse(v1.HasErrors); + + var v2 = await ((int?)123).Validate("value").None().ValidateAsync(); + Assert.IsTrue(v2.HasErrors); + + v2 = await ((int?)0).Validate("value").None().ValidateAsync(); + Assert.IsTrue(v2.HasErrors); + + v2 = await ((int?)null).Validate("value").None().ValidateAsync(); + Assert.IsFalse(v2.HasErrors); + } + + public class Foo + { + public string? Bar { get; set; } + } + + [Test] + public async Task Validate_Entity() + { + Foo? foo = new Foo(); + var v1 = await foo.Validate("value").None().ValidateAsync(); + Assert.IsTrue(v1.HasErrors); + Assert.AreEqual(1, v1.Messages!.Count); + Assert.AreEqual("Value must not be specified.", v1.Messages[0].Text); + Assert.AreEqual(MessageType.Error, v1.Messages[0].Type); + Assert.AreEqual("value", v1.Messages[0].Property); + + foo = null; + v1 = await foo.Validate("value").None().ValidateAsync(); + Assert.IsFalse(v1.HasErrors); + } + } +}