diff --git a/.editorconfig b/.editorconfig
index d894c777..579d7292 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,7 +6,7 @@ root = true
[*]
indent_style = space
vsspell_section_id = cb4a4387061549238f01a4c2739f296e
-vsspell_ignored_keywords_cb4a4387061549238f01a4c2739f296e = Mongo
+vsspell_ignored_keywords_cb4a4387061549238f01a4c2739f296e = Mongo|validators
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
@@ -141,4 +141,4 @@ csharp_preserve_single_line_blocks = true
###############################
[*.vb]
# Modifier preferences
-visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
\ No newline at end of file
+visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f156d20d..c763e539 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,6 +3,8 @@
+
+
diff --git a/src/API.Core/API.Core.csproj b/src/API.Core/API.Core.csproj
index 2291f0dd..45374c69 100644
--- a/src/API.Core/API.Core.csproj
+++ b/src/API.Core/API.Core.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/API.Core/Validators/ValidationBehavior.cs b/src/API.Core/Validators/ValidationBehavior.cs
new file mode 100644
index 00000000..2c94ac80
--- /dev/null
+++ b/src/API.Core/Validators/ValidationBehavior.cs
@@ -0,0 +1,31 @@
+using FluentValidation;
+using MediatR;
+
+namespace Fossa.API.Core.Validators;
+
+public class ValidationBehavior : IPipelineBehavior where TRequest : IRequest
+{
+ private readonly IEnumerable> _validators;
+
+ public ValidationBehavior(IEnumerable> validators)
+ {
+ _validators = validators;
+ }
+
+ public async Task Handle(
+ TRequest request,
+ RequestHandlerDelegate next,
+ CancellationToken cancellationToken)
+ {
+ if (_validators.Any())
+ {
+ var context = new ValidationContext(request);
+ var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken))).ConfigureAwait(false);
+ var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList();
+ if (failures.Count != 0)
+ throw new ValidationException(failures);
+ }
+
+ return await next().ConfigureAwait(false);
+ }
+}
diff --git a/src/API.Web/API.Web.csproj b/src/API.Web/API.Web.csproj
index e97f4e34..ef40a05e 100644
--- a/src/API.Web/API.Web.csproj
+++ b/src/API.Web/API.Web.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/API.Web/Program.cs b/src/API.Web/Program.cs
index 4d242a0b..e8f5032a 100644
--- a/src/API.Web/Program.cs
+++ b/src/API.Web/Program.cs
@@ -1,6 +1,8 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
+using FluentValidation;
using Fossa.API.Core;
+using Fossa.API.Core.Validators;
using Fossa.API.Infrastructure;
using Fossa.API.Persistence;
using Fossa.API.Web;
@@ -51,17 +53,22 @@
builder.Services.AddFrameworkPlatform();
-builder.Services.AddMediatR(cfg =>
-{
- cfg.RegisterServicesFromAssemblies(Seq(
+var assemblies = Seq(
typeof(DefaultCoreModule),
typeof(DefaultInfrastructureModule),
typeof(DefaultPersistenceModule),
typeof(DefaultWebModule))
.Map(x => x.Assembly)
- .ToArray());
+ .ToArray();
+
+builder.Services.AddMediatR(cfg =>
+{
+ cfg.RegisterServicesFromAssemblies(assemblies);
+ cfg.AddOpenBehavior(typeof(ValidationBehavior<,>));
});
+builder.Services.AddValidatorsFromAssemblies(assemblies);
+
builder.Services.Scan(scan => scan
.FromApplicationDependencies()
.AddClasses(classes => classes.AssignableTo(typeof(IMapper<,>)))