From e2a702af2ed18a09232f38cb249c6c882e5e633b Mon Sep 17 00:00:00 2001 From: kolan72 Date: Thu, 24 Jul 2025 14:54:59 +0300 Subject: [PATCH 01/11] Support .NET 8.0 and FluentValidation 12.0.0. --- src/ExpressValidator/ExpressValidator.csproj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ExpressValidator/ExpressValidator.csproj b/src/ExpressValidator/ExpressValidator.csproj index 2e9f057..2a09851 100644 --- a/src/ExpressValidator/ExpressValidator.csproj +++ b/src/ExpressValidator/ExpressValidator.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.0;net8.0 true 0.9.0 true @@ -19,6 +19,14 @@ 0.0.0.0 + + + + + + + + From c4f77f6dfb7b87519d52536a86d739104952cbd4 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Fri, 25 Jul 2025 13:25:35 +0300 Subject: [PATCH 02/11] Fix NU1504: Duplicate 'PackageReference' found --- src/ExpressValidator/ExpressValidator.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ExpressValidator/ExpressValidator.csproj b/src/ExpressValidator/ExpressValidator.csproj index 2a09851..21f9c27 100644 --- a/src/ExpressValidator/ExpressValidator.csproj +++ b/src/ExpressValidator/ExpressValidator.csproj @@ -45,6 +45,10 @@ 1701;1702;1591 + + $(NoWarn);NU1504 + + <_Parameter1>ExpressValidator.Tests From bc4c90570d2151612cdfd4a8a31044a355e40e05 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Fri, 25 Jul 2025 14:20:42 +0300 Subject: [PATCH 03/11] Package 0.3.9 version and update CHANGELOG.md. --- .../CHANGELOG.md | 7 +++++++ .../ExpressValidator.Extensions.DependencyInjection.csproj | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ExpressValidator.Extensions.DependencyInjection/CHANGELOG.md b/src/ExpressValidator.Extensions.DependencyInjection/CHANGELOG.md index e047ff9..9f9bb74 100644 --- a/src/ExpressValidator.Extensions.DependencyInjection/CHANGELOG.md +++ b/src/ExpressValidator.Extensions.DependencyInjection/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.3.9 + +- Update ExpressValidator nuget package. +- Update Microsoft nuget packages. +- Update Microsoft NuGet packages for ExpressValidator.Extensions.DependencyInjection.Tests. + + ## 0.3.7 - Update ExpressValidator nuget package. diff --git a/src/ExpressValidator.Extensions.DependencyInjection/ExpressValidator.Extensions.DependencyInjection.csproj b/src/ExpressValidator.Extensions.DependencyInjection/ExpressValidator.Extensions.DependencyInjection.csproj index 5a94f17..f3ae59b 100644 --- a/src/ExpressValidator.Extensions.DependencyInjection/ExpressValidator.Extensions.DependencyInjection.csproj +++ b/src/ExpressValidator.Extensions.DependencyInjection/ExpressValidator.Extensions.DependencyInjection.csproj @@ -3,7 +3,7 @@ netstandard2.0 true - 0.3.7 + 0.3.9 true Andrey Kolesnichenko MIT @@ -15,7 +15,7 @@ FluentValidation Validation DependencyInjection The ExpressValidator.Extensions.DependencyInjection package extends ExpressValidator to provide integration with Microsoft Dependency Injection. Copyright 2024 Andrey Kolesnichenko - 0.3.7.0 + 0.3.9.0 From 8ac5d1296af3f4c6f84c4207e3571187347993f1 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Fri, 22 Aug 2025 15:02:29 +0300 Subject: [PATCH 04/11] Update NUnit NuGet package to v4.4.0. --- .../ExpressValidator.Tests.csproj | 12 ++++++------ tests/ExpressValidator.Tests/packages.config | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ExpressValidator.Tests/ExpressValidator.Tests.csproj b/tests/ExpressValidator.Tests/ExpressValidator.Tests.csproj index faee7f7..2d107d5 100644 --- a/tests/ExpressValidator.Tests/ExpressValidator.Tests.csproj +++ b/tests/ExpressValidator.Tests/ExpressValidator.Tests.csproj @@ -1,6 +1,6 @@  - + @@ -45,11 +45,11 @@ ..\..\packages\FluentValidation.11.11.0\lib\netstandard2.0\FluentValidation.dll - - ..\..\packages\NUnit.4.3.2\lib\net462\nunit.framework.dll + + ..\..\packages\NUnit.4.4.0\lib\net462\nunit.framework.dll - - ..\..\packages\NUnit.4.3.2\lib\net462\nunit.framework.legacy.dll + + ..\..\packages\NUnit.4.4.0\lib\net462\nunit.framework.legacy.dll @@ -112,8 +112,8 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/tests/ExpressValidator.Tests/packages.config b/tests/ExpressValidator.Tests/packages.config index 1b3d233..3e49123 100644 --- a/tests/ExpressValidator.Tests/packages.config +++ b/tests/ExpressValidator.Tests/packages.config @@ -1,7 +1,7 @@  - + From 1a6cfc84ebff5a18be0d396eb8354272df5e42eb Mon Sep 17 00:00:00 2001 From: kolan72 Date: Tue, 26 Aug 2025 12:12:22 +0300 Subject: [PATCH 05/11] Fix `ExpressPropertyValidator` to prevent calling `Func` propertyFunc twice when a success handler is present. --- .../PropertyValidators/ExpressPropertyValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ExpressValidator/PropertyValidators/ExpressPropertyValidator.cs b/src/ExpressValidator/PropertyValidators/ExpressPropertyValidator.cs index 6bf297c..a0ad0f5 100644 --- a/src/ExpressValidator/PropertyValidators/ExpressPropertyValidator.cs +++ b/src/ExpressValidator/PropertyValidators/ExpressPropertyValidator.cs @@ -33,7 +33,7 @@ public void SetValidation(Action> action) if (_onSuccessValidation != null) { var value = _propertyFunc(obj); - var res = await _typeValidator.ValidateExAsync(_propertyFunc(obj), token); + var res = await _typeValidator.ValidateExAsync(value, token); if (res.IsValid) { _onSuccessValidation(value); From 746e138e5d60397dd04cc5b436c4c17a7a0f0a53 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Wed, 27 Aug 2025 13:26:21 +0300 Subject: [PATCH 06/11] Add test for `ValidateAsync` with both `WithValidation` and `WithAsyncValidation` in `ExpressValidatorBuilder`. --- .../ExpressValidatorTests.ForAsync.Tests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs index 38e7990..3b4b103 100644 --- a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs +++ b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs @@ -85,5 +85,20 @@ public async Task Should_ValidateAsync_Work_For_AsyncRules() ClassicAssert.AreEqual(true, result.IsValid); } + + [Test] + public async Task Should_ValidateAsync_When_Using_Combined_Validation_Strategy() + { + var result = await new ExpressValidatorBuilder() + .AddProperty(o => o.I) + .WithAsyncValidation(o => o.MustAsync(async (_, __) => { await Task.Delay(1); return false; })) + .AddFunc(o => o.PercentValue1 + o.PercentValue2, "percentSum") + .WithValidation(o => o.InclusiveBetween(0, 100)) + .Build() + .ValidateAsync(new ObjWithTwoPublicProps() { I = 1, PercentValue1 = 200 }); + + Assert.That(result.IsValid, Is.False); + Assert.That(result.Errors.Count, Is.EqualTo(2)); + } } } From b9355794a992b3fdcf5fc55a4483ffc462af8253 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Wed, 27 Aug 2025 13:58:34 +0300 Subject: [PATCH 07/11] Add test to ensure synchronous `Validate` throws `AsyncValidatorInvokedSynchronouslyException` if the builder has async rules. --- .../ExpressValidatorTests.ForAsync.Tests.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs index 3b4b103..57e1c23 100644 --- a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs +++ b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs @@ -22,6 +22,16 @@ public void Should_Validate_Throw_For_AsyncRule_ForProperty() Assert.That(exc.Message, Does.StartWith("Object validator has a property or field with asynchronous validation rules.")); } + [Test] + public void Should_Using_WithValidation_With_AsyncRule_Throw_AsyncValidatorInvokedSynchronouslyException_When_Validate() + { + var builder = new ExpressValidatorBuilder() + .AddProperty(o => o.I) + .WithValidation(o => o.MustAsync(async (_, __) => { await Task.Delay(1); return true; })) + .Build(); + Assert.Throws(() => builder.Validate(new ObjWithTwoPublicProps() { I = 1, S = "b" })); + } + [Test] public async Task Should_AsyncInvoke_SuccessValidationHandler_When_IsValid() { From 36276cb3691cc0f88e9d62fbde66e512eacdb701 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Wed, 27 Aug 2025 14:41:22 +0300 Subject: [PATCH 08/11] Add a test for the `ValidateAsync` method with simulated external services. --- .../ExpressValidatorTests.ForAsync.Tests.cs | 21 +++++++++++++++++++ .../ExpressValidator.Tests/ObjectsToTests.cs | 20 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs index 57e1c23..69040dc 100644 --- a/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs +++ b/tests/ExpressValidator.Tests/ExpressValidatorTests.ForAsync.Tests.cs @@ -110,5 +110,26 @@ public async Task Should_ValidateAsync_When_Using_Combined_Validation_Strategy() Assert.That(result.IsValid, Is.False); Assert.That(result.Errors.Count, Is.EqualTo(2)); } + + [Test] + [TestCase(true)] + [TestCase(false)] + public async Task Should_ValidateAsync_When_Used_In_External_API(bool valid) + { + const int customerId = 1; + var apiClient = new SomeExternalWebApiClient(valid ? 2 : customerId); + var customer = new Customer() { CustomerId = customerId }; + + var result = await new ExpressValidatorBuilder() + .AddProperty(o => o.CustomerId) + .WithAsyncValidation(o => o.MustAsync(async (id, cancellation) => + + !await apiClient.IdExistsAsync(id, cancellation))) + + .Build() + .ValidateAsync(customer); + + Assert.That(result.IsValid, Is.EqualTo(valid)); + } } } diff --git a/tests/ExpressValidator.Tests/ObjectsToTests.cs b/tests/ExpressValidator.Tests/ObjectsToTests.cs index f80a877..30bd8db 100644 --- a/tests/ExpressValidator.Tests/ObjectsToTests.cs +++ b/tests/ExpressValidator.Tests/ObjectsToTests.cs @@ -1,5 +1,8 @@ using FluentValidation; +using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace ExpressValidator.Tests { @@ -69,4 +72,21 @@ public class Customer public decimal CustomerDiscount { get; set; } public bool IsPreferredCustomer { get; set; } } + + public class SomeExternalWebApiClient + { + private readonly int _existedId; + + public SomeExternalWebApiClient(int existedId) + { + _existedId = existedId; + } + + public async Task IdExistsAsync(int id, CancellationToken token) + { + await Task.Delay(TimeSpan.FromTicks(1), token); + return _existedId == id; + } + + } } From 0c4fb263810410b8643869776e9dc1b29afb9946 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Wed, 27 Aug 2025 15:09:23 +0300 Subject: [PATCH 09/11] Add 'Asynchronous Validation' README Chapter. --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index a034748..a0648cf 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,28 @@ if(!result.IsValid) } ``` +## 💡 Asynchronous Validation + +If you want to add asynchronous FluentValidation rules such as `MustAsync` or `CustomAsync`, the recommended approach is to use the `WithAsyncValidation` method: +```csharp +//Checking if a user ID is already in use using an external web API: +var result = await new ExpressValidatorBuilder() + .AddProperty(o => o.CustomerId) + .WithAsyncValidation(o => o.MustAsync(async (id, cancellation) => + + !await apiClient.IdExistsAsync(id, cancellation))) + + .Build() + .ValidateAsync(customer); +``` +Once you've used this method at least once within the `ExpressValidatorBuilder`, you must call the `ValidateAsync` method on the resulting `ExpressValidator`. + +Calling `Validate` instead will result in an `InvalidOperationException`. + +Note: You can still use the `WithValidation` method for asynchronous rules, but in that case, ensure you call only `ValidateAsync`; otherwise, FluentValidation will throw an `AsyncValidatorInvokedSynchronouslyException`. + +As with FluentValidation itself, you can safely call `ValidateAsync` when both synchronous and asynchronous rules are present. + ## ⚙️ Modifying FluentValidation Validator Parameters Using Options To dynamically change the parameters of the `FluentValidation` validators: From 542caa3ff949b3cd727240522b8786081fa24215 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Sun, 31 Aug 2025 19:48:05 +0300 Subject: [PATCH 10/11] Remove redundant `PackageReference` to FluentValidation 11.11.0. --- src/ExpressValidator/ExpressValidator.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ExpressValidator/ExpressValidator.csproj b/src/ExpressValidator/ExpressValidator.csproj index bd4c034..2ce5bde 100644 --- a/src/ExpressValidator/ExpressValidator.csproj +++ b/src/ExpressValidator/ExpressValidator.csproj @@ -33,10 +33,6 @@ - - - - 1701;1702;1591 From 7fa57893c7a4d2e61317586d27093cac133f7123 Mon Sep 17 00:00:00 2001 From: kolan72 Date: Sun, 31 Aug 2025 20:02:26 +0300 Subject: [PATCH 11/11] Package 0.12.0 version and update CHANGELOG.md. --- CHANGELOG.md | 12 ++++++++++++ src/ExpressValidator/ExpressValidator.csproj | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc581c..c2ee3ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.12.0 + +- Support .NET 8.0 and FluentValidation 12.0.0. +- Fix `ExpressPropertyValidator` to prevent calling `Func` propertyFunc twice when a success handler is present. +- Fix NU1504: Duplicate 'PackageReference' found +- Update NUnit NuGet package to v4.4.0. +- Add test for `ValidateAsync` with both `WithValidation` and `WithAsyncValidation` in `ExpressValidatorBuilder`. +- Add test to ensure synchronous Validate throws `AsyncValidatorInvokedSynchronouslyException` if the builder has async rules. +- Add a test for the `ValidateAsync` method with simulated external services. +- Add 'Asynchronous Validation' README Chapter. + + ## 0.10.0 - Introduced the `QuickValidator.ValidateAsync(T, Action>, string, Action, CancellationToken)` extension method. diff --git a/src/ExpressValidator/ExpressValidator.csproj b/src/ExpressValidator/ExpressValidator.csproj index 2ce5bde..9cfb235 100644 --- a/src/ExpressValidator/ExpressValidator.csproj +++ b/src/ExpressValidator/ExpressValidator.csproj @@ -3,7 +3,7 @@ netstandard2.0;net8.0 true - 0.10.0 + 0.12.0 true Andrey Kolesnichenko ExpressValidator is a library that provides the ability to validate objects using the FluentValidation library, but without object inheritance from `AbstractValidator`. @@ -15,7 +15,7 @@ ExpressValidator.png NuGet.md - 0.10.0.0 + 0.12.0.0 0.0.0.0