diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj
index 7abba2b..9450b4e 100644
--- a/Demo/Demo.csproj
+++ b/Demo/Demo.csproj
@@ -18,6 +18,7 @@
+
diff --git a/Demo/Startup.cs b/Demo/Startup.cs
index ed21cbe..c26d25b 100644
--- a/Demo/Startup.cs
+++ b/Demo/Startup.cs
@@ -19,6 +19,7 @@ using PoweredSoft.CQRS.AspNetCore.Mvc;
using PoweredSoft.CQRS.DynamicQuery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.AspNetCore;
+using PoweredSoft.CQRS.GraphQL.FluentValidation;
using PoweredSoft.CQRS.GraphQL.HotChocolate;
using PoweredSoft.Data;
using PoweredSoft.Data.Core;
@@ -50,7 +51,9 @@ namespace Demo
services.AddPoweredSoftDataServices();
services.AddPoweredSoftDynamicQuery();
- services.AddPoweredSoftCQRS();
+ services
+ .AddPoweredSoftCQRS();
+
services
.AddControllers()
.AddPoweredSoftQueries()
@@ -65,8 +68,9 @@ namespace Demo
.AddMutationType(d => d.Name("Mutation"))
.AddPoweredSoftMutations();
+ services.AddPoweredSoftGraphQLFluentValidation();
- //services.AddSwaggerGen();
+ services.AddSwaggerGen();
}
private void AddDynamicQueries(IServiceCollection services)
diff --git a/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLFieldError.cs b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLFieldError.cs
new file mode 100644
index 0000000..f4fb65a
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLFieldError.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace PoweredSoft.CQRS.GraphQL.Abstractions
+{
+ public interface IGraphQLFieldError
+ {
+ string Field { get; set; }
+ List Errors { get; set; }
+ }
+}
diff --git a/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationResult.cs b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationResult.cs
new file mode 100644
index 0000000..1cc3d1d
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationResult.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace PoweredSoft.CQRS.GraphQL.Abstractions
+{
+ public interface IGraphQLValidationResult
+ {
+ bool IsValid { get; }
+
+ List Errors { get; }
+ }
+}
diff --git a/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationService.cs b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationService.cs
new file mode 100644
index 0000000..1c5dd22
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.Abstractions/IGraphQLValidationService.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PoweredSoft.CQRS.GraphQL.Abstractions
+{
+
+ public interface IGraphQLValidationService
+ {
+ Task ValidateObjectAsync(object subject, CancellationToken cancellationToken = default);
+ Task ValidateAsync(T subject, CancellationToken cancellationToken = default);
+ }
+}
diff --git a/PoweredSoft.CQRS.GraphQL.Abstractions/PoweredSoft.CQRS.GraphQL.Abstractions.csproj b/PoweredSoft.CQRS.GraphQL.Abstractions/PoweredSoft.CQRS.GraphQL.Abstractions.csproj
new file mode 100644
index 0000000..9f5c4f4
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.Abstractions/PoweredSoft.CQRS.GraphQL.Abstractions.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netstandard2.0
+
+
+
diff --git a/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFieldError.cs b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFieldError.cs
new file mode 100644
index 0000000..3125d25
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFieldError.cs
@@ -0,0 +1,11 @@
+using PoweredSoft.CQRS.GraphQL.Abstractions;
+using System.Collections.Generic;
+
+namespace PoweredSoft.CQRS.GraphQL.FluentValidation
+{
+ public class GraphQLFieldError : IGraphQLFieldError
+ {
+ public string Field { get; set; }
+ public List Errors { get; set; } = new List();
+ }
+}
diff --git a/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationResult.cs b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationResult.cs
new file mode 100644
index 0000000..c5f1ddb
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationResult.cs
@@ -0,0 +1,28 @@
+using FluentValidation.Results;
+using PoweredSoft.CQRS.GraphQL.Abstractions;
+using System.Collections.Generic;
+
+namespace PoweredSoft.CQRS.GraphQL.FluentValidation
+{
+ public class GraphQLFluentValidationResult : IGraphQLValidationResult
+ {
+ public bool IsValid => Errors.Count == 0;
+ public List Errors { get; } = new List();
+
+ public static GraphQLFluentValidationResult From(ValidationResult result)
+ {
+ var model = new GraphQLFluentValidationResult();
+ foreach (var error in result.Errors)
+ {
+ var fieldError = new GraphQLFieldError
+ {
+ Field = error.PropertyName
+ };
+ fieldError.Errors.Add(error.ErrorMessage);
+ model.Errors.Add(fieldError);
+ }
+
+ return model;
+ }
+ }
+}
diff --git a/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationService.cs b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationService.cs
new file mode 100644
index 0000000..516b912
--- /dev/null
+++ b/PoweredSoft.CQRS.GraphQL.FluentValidation/GraphQLFluentValidationService.cs
@@ -0,0 +1,47 @@
+using FluentValidation;
+using PoweredSoft.CQRS.GraphQL.Abstractions;
+using System;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PoweredSoft.CQRS.GraphQL.FluentValidation
+{
+ public class GraphQLFluentValidationService : IGraphQLValidationService
+ {
+ private readonly IServiceProvider serviceProvider;
+
+ public GraphQLFluentValidationService(IServiceProvider serviceProvider)
+ {
+ this.serviceProvider = serviceProvider;
+ }
+
+ public async Task ValidateAsync(T subject, CancellationToken cancellationToken = default)
+ {
+ var validationService = serviceProvider.GetService(typeof(IValidator)) as IValidator;
+ if (validationService == null)
+ return new GraphQLValidResult();
+
+ var result = await validationService.ValidateAsync(subject, cancellationToken);
+ if (!result.IsValid)
+ return GraphQLFluentValidationResult.From(result);
+
+ return new GraphQLValidResult();
+ }
+
+ public async Task ValidateObjectAsync(object subject, CancellationToken cancellationToken = default)
+ {
+ var validatorType = typeof(IValidator<>).MakeGenericType(subject.GetType());
+ var validationService = serviceProvider.GetService(validatorType) as IValidator;
+ if (validationService == null)
+ return new GraphQLValidResult();
+
+ var result = await validationService.ValidateAsync(new ValidationContext