Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Given a user context class of the following form:
<a id='snippet-contextimplementingdictionary'></a>
```cs
public class MyUserContext :
Dictionary<string, object>
Dictionary<string, object?>
{
public MyUserContext(string myProperty)
{
Expand Down Expand Up @@ -174,7 +174,7 @@ ExecutionOptions options = new()
Schema = schema,
Query = queryString,
Inputs = inputs,
UserContext = new Dictionary<string, object>
UserContext = new Dictionary<string, object?>
{
{
"MyUserContext",
Expand Down Expand Up @@ -325,7 +325,7 @@ public class QueryTests
[Fact]
public Task RunInputQuery()
{
var field = new Query().GetField("inputQuery");
var field = new Query().GetField("inputQuery")!;

GraphQLUserContext userContext = new();
FluentValidationExtensions.AddCacheToContext(
Expand All @@ -346,15 +346,15 @@ public class QueryTests
},
UserContext = userContext
};
var result = (Result) field.Resolver.Resolve(fieldContext);
var result = (Result) field.Resolver!.Resolve(fieldContext)!;
return Verifier.Verify(result);
}

[Fact]
public Task RunInvalidInputQuery()
{
Thread.CurrentThread.CurrentUICulture = new("en-US");
var field = new Query().GetField("inputQuery");
var field = new Query().GetField("inputQuery")!;

GraphQLUserContext userContext = new();
FluentValidationExtensions.AddCacheToContext(
Expand All @@ -373,7 +373,7 @@ public class QueryTests
UserContext = userContext
};
var exception = Assert.Throws<ValidationException>(
() => field.Resolver.Resolve(fieldContext));
() => field.Resolver!.Resolve(fieldContext));
return Verifier.Verify(exception.Message);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>6.3.0</Version>
<Version>6.3.1</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<PackageTags>GraphQL, Validation, FluentValidation</PackageTags>
<Description>Add FluentValidation (https://fluentvalidation.net/) support to GraphQL.net (https://github.com/graphql-dotnet/graphql-dotnet)</Description>
Expand Down
7 changes: 4 additions & 3 deletions src/GraphQL.FluentValidation/ArgumentTypeCacheBag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ static class ArgumentTypeCacheBag

public static void SetCache(this ExecutionOptions options, ValidatorTypeCache cache)
{
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (options.UserContext == null)
{
options.UserContext = new Dictionary<string, object>
options.UserContext = new Dictionary<string, object?>
{
{ key, cache }
};
Expand All @@ -21,7 +22,7 @@ public static void SetCache(this ExecutionOptions options, ValidatorTypeCache ca
AddValidatorCache(options.UserContext, cache);
}

internal static void AddValidatorCache(this IDictionary<string, object> dictionary, ValidatorTypeCache cache)
internal static void AddValidatorCache(this IDictionary<string, object?> dictionary, ValidatorTypeCache cache)
{
dictionary.Add(key, cache);
}
Expand All @@ -35,7 +36,7 @@ public static ValidatorTypeCache GetCache(this IResolveFieldContext context)

if (context.UserContext.TryGetValue(key, out var result))
{
return (ValidatorTypeCache)result;
return (ValidatorTypeCache)result!;
}

throw new($"Could not extract {nameof(ValidatorTypeCache)} from {nameof(IResolveFieldContext)}.{nameof(IResolveFieldContext.UserContext)}. It is possible {nameof(FluentValidationExtensions)}.{nameof(FluentValidationExtensions.UseFluentValidation)} was not used.");
Expand Down
10 changes: 5 additions & 5 deletions src/GraphQL.FluentValidation/ArgumentValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ public static class ArgumentValidation
/// <summary>
/// Validate an instance
/// </summary>
public static Task ValidateAsync<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object> userContext)
public static Task ValidateAsync<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object?> userContext)
=> ValidateAsync(cache, type, instance, userContext, null);

/// <summary>
/// Validate an instance
/// </summary>
public static async Task ValidateAsync<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object> userContext, IServiceProvider? provider, CancellationToken cancellation = default)
public static async Task ValidateAsync<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object?> userContext, IServiceProvider? provider, CancellationToken cancellation = default)
{
var currentType = (Type?)type;
var validationContext = default(ValidationContext<TArgument>);
Expand All @@ -49,13 +49,13 @@ public static async Task ValidateAsync<TArgument>(ValidatorTypeCache cache, Type
/// <summary>
/// Validate an instance
/// </summary>
public static void Validate<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object> userContext)
public static void Validate<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object?> userContext)
=> Validate(cache, type, instance, userContext, null);

/// <summary>
/// Validate an instance
/// </summary>
public static void Validate<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object> userContext, IServiceProvider? provider)
public static void Validate<TArgument>(ValidatorTypeCache cache, Type type, TArgument instance, IDictionary<string, object?> userContext, IServiceProvider? provider)
{
if (instance == null)
{
Expand Down Expand Up @@ -89,7 +89,7 @@ static void ThrowIfResults(IEnumerable<ValidationFailure> results)
}
}

static ValidationContext<TArgument> BuildValidationContext<TArgument>(TArgument instance, IDictionary<string, object> userContext)
static ValidationContext<TArgument> BuildValidationContext<TArgument>(TArgument instance, IDictionary<string, object?> userContext)
{
ValidationContext<TArgument> validationContext = new(instance);
validationContext.RootContextData.Add("UserContext", userContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@ public static partial class FluentValidationExtensions
/// Uses <see cref="IValidator.Validate(IValidationContext)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static TArgument GetValidatedArgument<TArgument>(this IResolveFieldContext context, string name, TArgument defaultValue = default!)
public static TArgument GetValidatedArgument<TArgument>(this IResolveFieldContext context, string name)
{
return GetValidatedArgument<TArgument>(context, name, default!);
}

/// <summary>
/// Wraps <see cref="ResolveFieldContextExtensions.GetArgument{TType}"/> to validate the resulting argument instance.
/// Uses <see cref="IValidator.Validate(IValidationContext)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static TArgument GetValidatedArgument<TArgument>(this IResolveFieldContext context, string name, TArgument defaultValue)
{
var argument = context.GetArgument(name, defaultValue);
var validatorCache = context.GetCache();
ArgumentValidation.Validate(validatorCache, typeof(TArgument), argument, context.UserContext, context.Schema as IServiceProvider);
//TODO: handle null
return argument!;
}

Expand All @@ -25,12 +34,22 @@ public static TArgument GetValidatedArgument<TArgument>(this IResolveFieldContex
/// Uses <see cref="IValidator.Validate(IValidationContext)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static object GetValidatedArgument(this IResolveFieldContext context, Type argumentType, string name, object? defaultValue = null)
public static object GetValidatedArgument(this IResolveFieldContext context, Type argumentType, string name)
{
return GetValidatedArgument(context, argumentType, name, null!);
}

/// <summary>
/// Wraps <see cref="ResolveFieldContextExtensions.GetArgument{TType}"/> to validate the resulting argument instance.
/// Uses <see cref="IValidator.Validate(IValidationContext)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static object GetValidatedArgument(this IResolveFieldContext context, Type argumentType, string name, object defaultValue)
{
var argument = context.GetArgument(argumentType, name, defaultValue);
var validatorCache = context.GetCache();
ArgumentValidation.Validate(validatorCache, argumentType, argument, context.UserContext, context.Schema as IServiceProvider);
return argument;
return argument!;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ public static partial class FluentValidationExtensions
/// Uses <see cref="IValidator.ValidateAsync(IValidationContext,CancellationToken)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static async Task<TArgument> GetValidatedArgumentAsync<TArgument>(this IResolveFieldContext context, string name, TArgument defaultValue = default!)
public static Task<TArgument> GetValidatedArgumentAsync<TArgument>(this IResolveFieldContext context, string name)
{
return GetValidatedArgumentAsync<TArgument>(context, name, default!);
}

/// <summary>
/// Wraps <see cref="ResolveFieldContextExtensions.GetArgument{TType}"/> to validate the resulting argument instance.
/// Uses <see cref="IValidator.ValidateAsync(IValidationContext,CancellationToken)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static async Task<TArgument> GetValidatedArgumentAsync<TArgument>(this IResolveFieldContext context, string name, TArgument defaultValue)
{
var argument = context.GetArgument(name, defaultValue);
var validatorCache = context.GetCache();
await ArgumentValidation.ValidateAsync(validatorCache, typeof(TArgument), argument, context.UserContext, context.Schema as IServiceProvider);
//TODO: handle null
return argument!;
}

Expand All @@ -27,12 +36,22 @@ public static async Task<TArgument> GetValidatedArgumentAsync<TArgument>(this IR
/// Uses <see cref="IValidator.ValidateAsync(IValidationContext,CancellationToken)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static async Task<object> GetValidatedArgumentAsync(this IResolveFieldContext context, Type argumentType, string name, object? defaultValue = null)
public static Task<object> GetValidatedArgumentAsync(this IResolveFieldContext context, Type argumentType, string name)
{
return GetValidatedArgumentAsync(context, argumentType, name, default!);
}

/// <summary>
/// Wraps <see cref="ResolveFieldContextExtensions.GetArgument{TType}"/> to validate the resulting argument instance.
/// Uses <see cref="IValidator.ValidateAsync(IValidationContext,CancellationToken)"/> to perform validation.
/// If a <see cref="ValidationException"/> occurs it will be converted to <see cref="ExecutionError"/>s by a field middleware.
/// </summary>
public static async Task<object> GetValidatedArgumentAsync(this IResolveFieldContext context, Type argumentType, string name, object defaultValue)
{
var argument = context.GetArgument(argumentType, name, defaultValue);
var validatorCache = context.GetCache();
await ArgumentValidation.ValidateAsync(validatorCache, argumentType, argument, context.UserContext, context.Schema as IServiceProvider);
return argument;
return argument!;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static T UserContext<T>(this IValidationContext validationContext)
/// Injects a <see cref="ValidatorTypeCache" /> instance into a user context for testing purposes.
/// </summary>
public static void AddCacheToContext<T>(T userContext, ValidatorTypeCache cache)
where T : Dictionary<string, object>
where T : Dictionary<string, object?>
{
userContext.AddValidatorCache(cache);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.1" />
<PackageReference Include="GraphQL" Version="4.5.0" />
<PackageReference Include="GraphQL" Version="4.6.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
<PackageReference Include="ProjectDefaults" Version="1.0.56" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" Condition="$(Configuration) == 'Release'" />
Expand Down
8 changes: 4 additions & 4 deletions src/SampleWeb.Tests/QueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class QueryTests
[Fact]
public Task RunInputQuery()
{
var field = new Query().GetField("inputQuery");
var field = new Query().GetField("inputQuery")!;

GraphQLUserContext userContext = new();
FluentValidationExtensions.AddCacheToContext(
Expand All @@ -36,15 +36,15 @@ public Task RunInputQuery()
},
UserContext = userContext
};
var result = (Result) field.Resolver.Resolve(fieldContext);
var result = (Result) field.Resolver!.Resolve(fieldContext)!;
return Verifier.Verify(result);
}

[Fact]
public Task RunInvalidInputQuery()
{
Thread.CurrentThread.CurrentUICulture = new("en-US");
var field = new Query().GetField("inputQuery");
var field = new Query().GetField("inputQuery")!;

GraphQLUserContext userContext = new();
FluentValidationExtensions.AddCacheToContext(
Expand All @@ -63,7 +63,7 @@ public Task RunInvalidInputQuery()
UserContext = userContext
};
var exception = Assert.Throws<ValidationException>(
() => field.Resolver.Resolve(fieldContext));
() => field.Resolver!.Resolve(fieldContext));
return Verifier.Verify(exception.Message);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/SampleWeb.Tests/SampleWeb.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net5</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GraphQL" Version="4.5.0" />
<PackageReference Include="GraphQL" Version="4.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.9" />
<PackageReference Include="Xunit" Version="2.4.1" />
<PackageReference Include="Verify.Xunit" Version="11.24.0" />
Expand Down
2 changes: 1 addition & 1 deletion src/SampleWeb/GraphQlUserContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Generic;

public class GraphQLUserContext :
Dictionary<string, object>
Dictionary<string, object?>
{
}
2 changes: 1 addition & 1 deletion src/SampleWeb/SampleWeb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Folder Include="wwwroot\" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="10.3.1" />
<PackageReference Include="graphiql" Version="2.0.0" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="4.5.0" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="4.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.9" />
<ProjectReference Include="..\GraphQL.FluentValidation\GraphQL.FluentValidation.csproj" />
<PackageReference Include="ProjectDefaults" Version="1.0.56" PrivateAssets="All" />
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/Arguments/ComplexInputInnerGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public ComplexInputInnerGraph()
{
Field<StringGraphType, string?>()
.Name("content")
.Resolve(ctx => ctx.Source.Content);
.Resolve(ctx => ctx.Source!.Content);
}
}
4 changes: 2 additions & 2 deletions src/Tests/Arguments/ComplexInputListItemGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ public ComplexInputListItemGraph()
{
Field<NonNullGraphType<IntGraphType>>()
.Name("id")
.Resolve(ctx => ctx.Source.Id);
.Resolve(ctx => ctx.Source!.Id);

Field<StringGraphType, string?>()
.Name("content")
.Resolve(ctx => ctx.Source.Content);
.Resolve(ctx => ctx.Source!.Content);
}
}
4 changes: 2 additions & 2 deletions src/Tests/Snippets/QueryExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async Task ExecuteQuery()
#region ContextImplementingDictionary

public class MyUserContext :
Dictionary<string, object>
Dictionary<string, object?>
{
public MyUserContext(string myProperty)
{
Expand Down Expand Up @@ -86,7 +86,7 @@ void ExecuteQueryWithContextInsideDictionary()
Schema = schema,
Query = queryString,
Inputs = inputs,
UserContext = new Dictionary<string, object>
UserContext = new Dictionary<string, object?>
{
{
"MyUserContext",
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.1" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="4.5.0" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="4.6.0" />
<PackageReference Include="Xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
Expand Down