diff --git a/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ClassLibrary1.csproj b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ClassLibrary1.csproj
new file mode 100644
index 000000000..b16aab1dd
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ClassLibrary1.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net10.0
+ enable
+
+
+
+
+
+
+
diff --git a/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/FluentValidationExtensions.cs b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/FluentValidationExtensions.cs
new file mode 100644
index 000000000..c828e9d43
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/FluentValidationExtensions.cs
@@ -0,0 +1,14 @@
+using FluentValidation;
+
+namespace ClassLibrary1
+{
+ public static class FluentValidationExtensions
+ {
+ public static IRuleBuilderOptions FullName(this IRuleBuilder ruleBuilder)
+ {
+ return ruleBuilder.MinimumLength(10)
+ .Must(val => val.Split(" ").Length == 2)
+ .WithMessage("Name must contain a single space and be at least 10 characters long");
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/Order.cs b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/Order.cs
new file mode 100644
index 000000000..86b3a045b
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/Order.cs
@@ -0,0 +1,23 @@
+namespace ClassLibrary1
+{
+ public class Order
+ {
+ public string CustomerName { get; set; }
+ public int Price { get; set; }
+ public string CustomerEmail { get; set; }
+ public OrderStatus OrderStatus { get; set; }
+ public Product[] Products { get; set; }
+ }
+
+ public class Product
+ {
+ public string Name { get; set; }
+ }
+
+ public enum OrderStatus
+ {
+ Accepted,
+ Processing,
+ Complete
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/OrderValidator.cs b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/OrderValidator.cs
new file mode 100644
index 000000000..827498464
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/OrderValidator.cs
@@ -0,0 +1,16 @@
+using FluentValidation;
+
+namespace ClassLibrary1
+{
+ public class OrderValidator : AbstractValidator
+ {
+ public OrderValidator()
+ {
+ RuleFor(model => model.CustomerName).FullName();
+ RuleFor(model => model.CustomerEmail).Cascade(CascadeMode.Stop).EmailAddress().MinimumLength(20);
+ RuleFor(model => model.Price).InclusiveBetween(1, 1000);
+ RuleFor(model => model.OrderStatus).IsInEnum();
+ RuleForEach(model => model.Products).SetValidator(new ProductValidator());
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ProductValidator.cs b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ProductValidator.cs
new file mode 100644
index 000000000..60ae28e0b
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/ClassLibrary1/ProductValidator.cs
@@ -0,0 +1,12 @@
+using FluentValidation;
+
+namespace ClassLibrary1
+{
+ public class ProductValidator : AbstractValidator
+ {
+ public ProductValidator()
+ {
+ RuleFor(model => model.Name).NotEmpty();
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/FluentValidationValidators.sln b/dotnet-client-libraries/FluentValidationValidators/FluentValidationValidators.sln
new file mode 100644
index 000000000..ea22e4e28
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/FluentValidationValidators.sln
@@ -0,0 +1,62 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication1", "WebApplication1\WebApplication1.csproj", "{209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{A5C5A8F0-33DE-422D-B41D-811514D33353}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|x64.Build.0 = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Debug|x86.Build.0 = Debug|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|x64.ActiveCfg = Release|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|x64.Build.0 = Release|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|x86.ActiveCfg = Release|Any CPU
+ {D53ED5E5-4F4D-4B88-8D63-B1A11CC83475}.Release|x86.Build.0 = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|x64.Build.0 = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Debug|x86.Build.0 = Debug|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|x64.ActiveCfg = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|x64.Build.0 = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|x86.ActiveCfg = Release|Any CPU
+ {209EDB45-BFE8-4F1B-A0B9-9EF30A3D4D6D}.Release|x86.Build.0 = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|x64.Build.0 = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Debug|x86.Build.0 = Debug|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|x64.ActiveCfg = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|x64.Build.0 = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|x86.ActiveCfg = Release|Any CPU
+ {A5C5A8F0-33DE-422D-B41D-811514D33353}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet-client-libraries/FluentValidationValidators/README.md b/dotnet-client-libraries/FluentValidationValidators/README.md
new file mode 100644
index 000000000..63cc702e9
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/README.md
@@ -0,0 +1,31 @@
+## FluentValidation Validators in C#: Built-in and Custom
+
+Source code for [FluentValidation Validators in C#: Built-in and Custom](https://code-maze.com/deep-dive-validators-fluentvalidation/).
+
+| Folder | What it is |
+| - | - |
+| `ClassLibrary1` | The validators themselves — `Order`, `Product`, `OrderValidator`, `ProductValidator`, and the `FullName()` custom validator written as an extension method on `IRuleBuilder`. |
+| `WebApplication1` | An ASP.NET Core API that references the class library, registers every validator with `AddValidatorsFromAssemblyContaining()`, and invokes `IValidator` explicitly in `OrdersController`. |
+| `Tests` | Tests over the validators: the custom `FullName()` message, `CascadeMode.Stop` reporting one failure instead of two, `IsInEnum()` rejecting an undeclared member, `RuleForEach()` reporting the item index, and the exact strings `EmailAddress()` does and does not accept. |
+
+Everything targets .NET 10 and FluentValidation 12.
+
+```
+dotnet build FluentValidationValidators.sln
+dotnet test FluentValidationValidators.sln
+```
+
+### A note on `FluentValidation.AspNetCore`
+
+The API project does **not** reference `FluentValidation.AspNetCore`, and this is
+deliberate on two counts.
+
+The package stops at **11.3.1** — there is no 12.x — so it cannot be paired with
+FluentValidation 12.1.1. And the automatic-validation pipeline it provides is the
+approach FluentValidation's own ASP.NET Core documentation says it "no longer
+recommend[s] ... for new projects", while still supporting it for legacy code.
+
+The current path is the one this sample uses: register the validators with
+`AddValidatorsFromAssemblyContaining()` from
+`FluentValidation.DependencyInjectionExtensions`, inject `IValidator`, and call
+`ValidateAsync()` where the validation belongs.
diff --git a/dotnet-client-libraries/FluentValidationValidators/Tests/BuiltInValidatorBehaviourTests.cs b/dotnet-client-libraries/FluentValidationValidators/Tests/BuiltInValidatorBehaviourTests.cs
new file mode 100644
index 000000000..9ee0fe5b4
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/Tests/BuiltInValidatorBehaviourTests.cs
@@ -0,0 +1,50 @@
+using FluentValidation;
+
+namespace Tests;
+
+///
+/// These tests pin the two library behaviours the article states as facts, so that a package
+/// bump that changes either of them fails CI instead of silently making the article wrong.
+///
+[TestClass]
+public class BuiltInValidatorBehaviourTests
+{
+ private class EmailHolder
+ {
+ public string Email { get; set; }
+ }
+
+ private class EmailHolderValidator : AbstractValidator
+ {
+ public EmailHolderValidator() => RuleFor(model => model.Email).EmailAddress();
+ }
+
+ private static bool IsAcceptedAsEmail(string value)
+ => new EmailHolderValidator().Validate(new EmailHolder { Email = value }).IsValid;
+
+ [TestMethod]
+ [DataRow("joebloggs@someemaildomain.com")]
+ [DataRow("a@b")]
+ [DataRow("has space@x.com")]
+ public void EmailAddressValidator_AcceptsAnythingWithASingleAtSign(string value)
+ {
+ Assert.IsTrue(IsAcceptedAsEmail(value));
+ }
+
+ [TestMethod]
+ [DataRow("not-an-email")]
+ [DataRow("plain")]
+ [DataRow("a@b@c")]
+ public void EmailAddressValidator_RejectsValuesWithoutExactlyOneAtSign(string value)
+ {
+ Assert.IsFalse(IsAcceptedAsEmail(value));
+ }
+
+ [TestMethod]
+ public void CascadeMode_DeclaresOnlyContinueAndStop()
+ {
+ CollectionAssert.AreEquivalent(
+ new[] { "Continue", "Stop" },
+ Enum.GetNames());
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/Tests/OrderValidatorTests.cs b/dotnet-client-libraries/FluentValidationValidators/Tests/OrderValidatorTests.cs
new file mode 100644
index 000000000..c86869bb3
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/Tests/OrderValidatorTests.cs
@@ -0,0 +1,87 @@
+using ClassLibrary1;
+using FluentValidation;
+
+namespace Tests;
+
+[TestClass]
+public class OrderValidatorTests
+{
+ private readonly OrderValidator _validator = new();
+
+ private static Order ValidOrder() => new()
+ {
+ CustomerName = "Joe Bloggsworth",
+ CustomerEmail = "joebloggs@someemaildomain.com",
+ Price = 100,
+ OrderStatus = OrderStatus.Accepted,
+ Products = [new Product { Name = "Keyboard" }]
+ };
+
+ [TestMethod]
+ public void WhenOrderIsValid_ThenValidationSucceeds()
+ {
+ var result = _validator.Validate(ValidOrder());
+
+ Assert.IsTrue(result.IsValid);
+ Assert.AreEqual(0, result.Errors.Count);
+ }
+
+ [TestMethod]
+ public void WhenCustomerNameHasNoSpace_ThenFullNameValidatorReportsItsOwnMessage()
+ {
+ var order = ValidOrder();
+ order.CustomerName = "JoeBloggsworth";
+
+ var result = _validator.Validate(order);
+
+ Assert.IsFalse(result.IsValid);
+ var failure = result.Errors.Single(e => e.PropertyName == nameof(Order.CustomerName));
+ Assert.AreEqual("Name must contain a single space and be at least 10 characters long", failure.ErrorMessage);
+ }
+
+ [TestMethod]
+ public void WhenCascadeModeIsStop_ThenOnlyTheFirstEmailFailureIsReported()
+ {
+ var order = ValidOrder();
+ order.CustomerEmail = "AAAAA";
+
+ var result = _validator.Validate(order);
+
+ var emailFailures = result.Errors.Where(e => e.PropertyName == nameof(Order.CustomerEmail)).ToList();
+ Assert.AreEqual(1, emailFailures.Count);
+ StringAssert.Contains(emailFailures[0].ErrorMessage, "valid email address");
+ }
+
+ [TestMethod]
+ public void WhenOrderStatusIsNotADeclaredMember_ThenIsInEnumRejectsIt()
+ {
+ var order = ValidOrder();
+ order.OrderStatus = (OrderStatus)42;
+
+ var result = _validator.Validate(order);
+
+ Assert.IsFalse(result.IsValid);
+ Assert.IsTrue(result.Errors.Any(e => e.PropertyName == nameof(Order.OrderStatus)));
+ }
+
+ [TestMethod]
+ public void WhenOneProductIsInvalid_ThenRuleForEachReportsTheItemIndex()
+ {
+ var order = ValidOrder();
+ order.Products = [new Product { Name = "Keyboard" }, new Product { Name = string.Empty }];
+
+ var result = _validator.Validate(order);
+
+ Assert.IsFalse(result.IsValid);
+ Assert.AreEqual("Products[1].Name", result.Errors.Single().PropertyName);
+ }
+
+ [TestMethod]
+ public void WhenValidationFails_ThenValidateAndThrowThrowsValidationException()
+ {
+ var order = ValidOrder();
+ order.Price = 5000;
+
+ Assert.ThrowsExactly(() => _validator.ValidateAndThrow(order));
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/Tests/Tests.csproj b/dotnet-client-libraries/FluentValidationValidators/Tests/Tests.csproj
new file mode 100644
index 000000000..2e50ee6e5
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/Tests/Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net10.0
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/OrdersController.cs b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/OrdersController.cs
new file mode 100644
index 000000000..a7033d7dc
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/OrdersController.cs
@@ -0,0 +1,36 @@
+using ClassLibrary1;
+using FluentValidation;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApplication1.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class OrdersController : ControllerBase
+ {
+ private readonly IValidator _validator;
+
+ public OrdersController(IValidator validator)
+ {
+ _validator = validator;
+ }
+
+ [HttpPost]
+ public async Task Post([FromBody] Order order)
+ {
+ var validationResult = await _validator.ValidateAsync(order);
+
+ if (!validationResult.IsValid)
+ {
+ foreach (var error in validationResult.Errors)
+ {
+ ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
+ }
+
+ return ValidationProblem(ModelState);
+ }
+
+ return Ok("Success!");
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/WeatherForecastController.cs b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/WeatherForecastController.cs
new file mode 100644
index 000000000..d0c0b03b4
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Controllers/WeatherForecastController.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApplication1.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class WeatherForecastController : ControllerBase
+ {
+ private static readonly string[] Summaries =
+ [
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ ];
+
+ [HttpGet]
+ public IEnumerable Get()
+ {
+ return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+ {
+ Date = DateTime.Now.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = Summaries[Random.Shared.Next(Summaries.Length)]
+ })
+ .ToArray();
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Program.cs b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Program.cs
new file mode 100644
index 000000000..767219517
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Program.cs
@@ -0,0 +1,20 @@
+using ClassLibrary1;
+using FluentValidation;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddControllers();
+builder.Services.AddValidatorsFromAssemblyContaining();
+
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
+{
+ app.UseDeveloperExceptionPage();
+}
+
+app.UseHttpsRedirection();
+app.UseAuthorization();
+app.MapControllers();
+
+app.Run();
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Properties/launchSettings.json b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Properties/launchSettings.json
new file mode 100644
index 000000000..58ad4e054
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/Properties/launchSettings.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:53840",
+ "sslPort": 44314
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "WebApplication1": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WeatherForecast.cs b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WeatherForecast.cs
new file mode 100644
index 000000000..41c1e7e90
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WeatherForecast.cs
@@ -0,0 +1,13 @@
+namespace WebApplication1
+{
+ public class WeatherForecast
+ {
+ public DateTime Date { get; set; }
+
+ public int TemperatureC { get; set; }
+
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+ public string Summary { get; set; }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WebApplication1.csproj b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WebApplication1.csproj
new file mode 100644
index 000000000..ce98df856
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/WebApplication1.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net10.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.Development.json b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.Development.json
new file mode 100644
index 000000000..8983e0fc1
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.json b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.json
new file mode 100644
index 000000000..d9d9a9bff
--- /dev/null
+++ b/dotnet-client-libraries/FluentValidationValidators/WebApplication1/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/dotnet-client-libraries/README.md b/dotnet-client-libraries/README.md
index 1f5b8dfac..d232baf3a 100644
--- a/dotnet-client-libraries/README.md
+++ b/dotnet-client-libraries/README.md
@@ -59,3 +59,4 @@ This section contains the topics about the client libraries in .NET.
- [Introduction to the Wolverine Library in .NET](https://code-maze.com/dotnet-wolverine-library/)
- [Comparison of Rebus, NServiceBus, and MassTransit in .NET](https://code-maze.com/aspnetcore-comparison-of-rebus-nservicebus-and-masstransit/)
- [Polly in .NET: Retry, Circuit Breaker, and Fallback](https://code-maze.com/creating-resilient-microservices-in-net-with-polly/)
+- [FluentValidation Validators in C#: Built-in and Custom](https://code-maze.com/deep-dive-validators-fluentvalidation/)