diff --git a/src/CookieCrumble/src/CookieCrumble/CookieCrumble.csproj b/src/CookieCrumble/src/CookieCrumble/CookieCrumble.csproj
index e81c6cbf372..5bebb73f26a 100644
--- a/src/CookieCrumble/src/CookieCrumble/CookieCrumble.csproj
+++ b/src/CookieCrumble/src/CookieCrumble/CookieCrumble.csproj
@@ -5,7 +5,6 @@
enable
enable
true
- false
CookieCrumble
CookieCrumble
diff --git a/src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs b/src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs
index b7b90dfeb17..58685aecda2 100644
--- a/src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs
+++ b/src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs
@@ -5,7 +5,7 @@
namespace HotChocolate.Execution.Configuration;
-public class RequestExecutorSetup
+public sealed class RequestExecutorSetup
{
private readonly List _schemaBuilderActions = new();
private readonly List _requestExecutorOptionsActions = new();
diff --git a/src/HotChocolate/Core/src/Execution/Serialization/JsonResultFormatter.cs b/src/HotChocolate/Core/src/Execution/Serialization/JsonResultFormatter.cs
index c36cae9f5bc..b31ff9302ce 100644
--- a/src/HotChocolate/Core/src/Execution/Serialization/JsonResultFormatter.cs
+++ b/src/HotChocolate/Core/src/Execution/Serialization/JsonResultFormatter.cs
@@ -6,6 +6,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
+using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using HotChocolate.Execution.Processing;
@@ -644,6 +645,10 @@ private void WriteIncremental(Utf8JsonWriter writer, IReadOnlyList
break;
#if NET6_0_OR_GREATER
+ case JsonDocument doc:
+ WriteJsonElement(writer, doc.RootElement);
+ break;
+
case JsonElement element:
WriteJsonElement(writer, element);
break;
diff --git a/src/HotChocolate/Core/src/Execution/Serialization/RawJsonValue.cs b/src/HotChocolate/Core/src/Execution/Serialization/RawJsonValue.cs
index 5062c96761b..564cccb4d08 100644
--- a/src/HotChocolate/Core/src/Execution/Serialization/RawJsonValue.cs
+++ b/src/HotChocolate/Core/src/Execution/Serialization/RawJsonValue.cs
@@ -9,11 +9,12 @@ namespace HotChocolate.Execution.Serialization;
/// and writes it without validation to the JSON response object.
///
///
+///
/// The downside of this helper is that we bind it explicitly to JSON.
/// If there were alternative query formatter that use different formats we would get
/// into trouble with this.
-///
-/// This is also the reason for keeping this internal.
+///
+/// This is also the reason for keeping this internal.
///
internal readonly struct RawJsonValue
{
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/DirectiveTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/DirectiveTypeAttribute.cs
index c40f914af70..d53d64fb87a 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/DirectiveTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/DirectiveTypeAttribute.cs
@@ -45,5 +45,6 @@ public DirectiveTypeAttribute(string name, DirectiveLocation location)
}
descriptor.Location(Location);
+ descriptor.Extend().Definition.Arguments.BindingBehavior = BindingBehavior.Implicit;
}
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeAttribute.cs
index c87b1499984..15643f40ceb 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeAttribute.cs
@@ -42,5 +42,7 @@ public EnumTypeAttribute(string? name = null)
{
descriptor.Name(Name);
}
+
+ descriptor.BindValuesImplicitly();
}
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs
index 573f33943e7..6a37b3b96fb 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs
@@ -10,8 +10,7 @@ namespace HotChocolate.Types;
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct,
Inherited = true,
AllowMultiple = true)]
-public abstract class EnumTypeDescriptorAttribute
- : DescriptorAttribute
+public abstract class EnumTypeDescriptorAttribute : DescriptorAttribute
{
protected internal sealed override void TryConfigure(
IDescriptorContext context,
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumValueDescriptorAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumValueDescriptorAttribute.cs
index 980c5c8cbdc..00e37c070cd 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/EnumValueDescriptorAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/EnumValueDescriptorAttribute.cs
@@ -10,8 +10,7 @@ namespace HotChocolate.Types;
AttributeTargets.Field,
Inherited = true,
AllowMultiple = true)]
-public abstract class EnumValueDescriptorAttribute
- : DescriptorAttribute
+public abstract class EnumValueDescriptorAttribute : DescriptorAttribute
{
protected internal sealed override void TryConfigure(
IDescriptorContext context,
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/ExtendObjectTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/ExtendObjectTypeAttribute.cs
index 087065b09f5..72003e3fc07 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/ExtendObjectTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/ExtendObjectTypeAttribute.cs
@@ -102,9 +102,12 @@ public ExtendObjectTypeAttribute(Type extendsType)
descriptor.Name(Name);
}
+ var definition = descriptor.Extend().Definition;
+ definition.Fields.BindingBehavior = BindingBehavior.Implicit;
+
if (IncludeStaticMembers)
{
- descriptor.Extend().Definition.FieldBindingFlags = Instance | Static;
+ definition.FieldBindingFlags = Instance | Static;
}
if (IgnoreFields is not null)
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/InputObjectTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/InputObjectTypeAttribute.cs
index 2c27cc225a0..9d5bab71162 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/InputObjectTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/InputObjectTypeAttribute.cs
@@ -41,5 +41,7 @@ public InputObjectTypeAttribute(string? name = null)
{
descriptor.Name(Name);
}
+
+ descriptor.Extend().Definition.Fields.BindingBehavior = BindingBehavior.Implicit;
}
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/InterfaceTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/InterfaceTypeAttribute.cs
index 52642532629..b8706ce6998 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/InterfaceTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/InterfaceTypeAttribute.cs
@@ -41,5 +41,7 @@ public InterfaceTypeAttribute(string? name = null)
{
descriptor.Name(Name);
}
+
+ descriptor.Extend().Definition.Fields.BindingBehavior = BindingBehavior.Implicit;
}
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/MutationTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/MutationTypeAttribute.cs
index 1a808a7a06a..c874dddb03f 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/MutationTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/MutationTypeAttribute.cs
@@ -16,6 +16,11 @@ public sealed class MutationTypeAttribute
///
public bool Inherited { get; set; }
+ ///
+ /// Defines that static members are included.
+ ///
+ public bool IncludeStaticMembers { get; set; }
+
TypeKind ITypeAttribute.Kind => TypeKind.Object;
bool ITypeAttribute.IsTypeExtension => true;
@@ -24,5 +29,15 @@ public sealed class MutationTypeAttribute
IDescriptorContext context,
IObjectTypeDescriptor descriptor,
Type type)
- => descriptor.Name(OperationTypeNames.Mutation);
+ {
+ descriptor.Name(OperationTypeNames.Mutation);
+
+ var definition = descriptor.Extend().Definition;
+ definition.Fields.BindingBehavior = BindingBehavior.Implicit;
+
+ if (IncludeStaticMembers)
+ {
+ definition.FieldBindingFlags = FieldBindingFlags.Instance | FieldBindingFlags.Static;
+ }
+ }
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/ObjectTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/ObjectTypeAttribute.cs
index b7443c348cd..a9a6ad3ad09 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/ObjectTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/ObjectTypeAttribute.cs
@@ -53,9 +53,12 @@ public ObjectTypeAttribute(string? name = null)
descriptor.Name(Name);
}
+ var definition = descriptor.Extend().Definition;
+ definition.Fields.BindingBehavior = BindingBehavior.Implicit;
+
if (IncludeStaticMembers)
{
- descriptor.Extend().Definition.FieldBindingFlags = Instance | Static;
+ definition.FieldBindingFlags = Instance | Static;
}
}
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/QueryTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/QueryTypeAttribute.cs
index ba850d793a6..5df7d435dce 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/QueryTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/QueryTypeAttribute.cs
@@ -16,6 +16,11 @@ public sealed class QueryTypeAttribute
///
public bool Inherited { get; set; }
+ ///
+ /// Defines that static members are included.
+ ///
+ public bool IncludeStaticMembers { get; set; }
+
TypeKind ITypeAttribute.Kind => TypeKind.Object;
bool ITypeAttribute.IsTypeExtension => true;
@@ -24,5 +29,15 @@ public sealed class QueryTypeAttribute
IDescriptorContext context,
IObjectTypeDescriptor descriptor,
Type type)
- => descriptor.Name(OperationTypeNames.Query);
+ {
+ descriptor.Name(OperationTypeNames.Query);
+
+ var definition = descriptor.Extend().Definition;
+ definition.Fields.BindingBehavior = BindingBehavior.Implicit;
+
+ if (IncludeStaticMembers)
+ {
+ definition.FieldBindingFlags = FieldBindingFlags.Instance | FieldBindingFlags.Static;
+ }
+ }
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/StreamResultAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/StreamResultAttribute.cs
index 4c83d31e22c..06be527a764 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/StreamResultAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/StreamResultAttribute.cs
@@ -16,7 +16,5 @@ public sealed class StreamResultAttribute : ObjectFieldDescriptorAttribute
IDescriptorContext context,
IObjectFieldDescriptor descriptor,
MemberInfo member)
- {
- descriptor.StreamResult();
- }
+ => descriptor.StreamResult();
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Attributes/SubscriptionTypeAttribute.cs b/src/HotChocolate/Core/src/Types/Types/Attributes/SubscriptionTypeAttribute.cs
index 8282e879217..4f910fa5532 100644
--- a/src/HotChocolate/Core/src/Types/Types/Attributes/SubscriptionTypeAttribute.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Attributes/SubscriptionTypeAttribute.cs
@@ -16,6 +16,11 @@ public sealed class SubscriptionTypeAttribute
///
public bool Inherited { get; set; }
+ ///
+ /// Defines that static members are included.
+ ///
+ public bool IncludeStaticMembers { get; set; }
+
TypeKind ITypeAttribute.Kind => TypeKind.Object;
bool ITypeAttribute.IsTypeExtension => true;
@@ -24,5 +29,15 @@ public sealed class SubscriptionTypeAttribute
IDescriptorContext context,
IObjectTypeDescriptor descriptor,
Type type)
- => descriptor.Name(OperationTypeNames.Subscription);
+ {
+ descriptor.Name(OperationTypeNames.Subscription);
+
+ var definition = descriptor.Extend().Definition;
+ definition.Fields.BindingBehavior = BindingBehavior.Implicit;
+
+ if (IncludeStaticMembers)
+ {
+ definition.FieldBindingFlags = FieldBindingFlags.Instance | FieldBindingFlags.Static;
+ }
+ }
}
diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DefaultNamingConventions.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DefaultNamingConventions.cs
index 989cfff15fb..91bf2735bda 100644
--- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DefaultNamingConventions.cs
+++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DefaultNamingConventions.cs
@@ -10,7 +10,7 @@ namespace HotChocolate.Types.Descriptors;
public class DefaultNamingConventions
: Convention
- , INamingConventions
+ , INamingConventions
{
private const string _inputPostfix = "Input";
private const string _inputTypePostfix = "InputType";
diff --git a/src/HotChocolate/Core/src/Types/Types/InputObjectType~1.cs b/src/HotChocolate/Core/src/Types/Types/InputObjectType~1.cs
index 8d215e24e2d..d8eb187cf87 100644
--- a/src/HotChocolate/Core/src/Types/Types/InputObjectType~1.cs
+++ b/src/HotChocolate/Core/src/Types/Types/InputObjectType~1.cs
@@ -2,6 +2,7 @@
using HotChocolate.Configuration;
using HotChocolate.Types.Descriptors;
using HotChocolate.Types.Descriptors.Definitions;
+using HotChocolate.Types.Helpers;
#nullable enable
@@ -29,14 +30,6 @@ public InputObjectType(Action> configure)
_configure!(descriptor);
_configure = null;
- // if the object type is inferred from a runtime time we will bind fields implicitly
- // even if the schema building option are set to bind explicitly by default;
- // otherwise we would end up with types that have no fields.
- if (context.IsInferred)
- {
- descriptor.BindFieldsImplicitly();
- }
-
return descriptor.CreateDefinition();
}
diff --git a/src/HotChocolate/Core/src/Types/Types/InterfaceType~1.cs b/src/HotChocolate/Core/src/Types/Types/InterfaceType~1.cs
index 67f7b06eac1..53e98eab093 100644
--- a/src/HotChocolate/Core/src/Types/Types/InterfaceType~1.cs
+++ b/src/HotChocolate/Core/src/Types/Types/InterfaceType~1.cs
@@ -24,14 +24,6 @@ protected override InterfaceTypeDefinition CreateDefinition(ITypeDiscoveryContex
_configure!(descriptor);
_configure = null;
- // if the object type is inferred from a runtime time we will bind fields implicitly
- // even if the schema building option are set to bind explicitly by default;
- // otherwise we would end up with types that have no fields.
- if (context.IsInferred)
- {
- descriptor.BindFieldsImplicitly();
- }
-
return descriptor.CreateDefinition();
}
diff --git a/src/HotChocolate/Core/src/Types/Types/ObjectTypeExtension~1.cs b/src/HotChocolate/Core/src/Types/Types/ObjectTypeExtension~1.cs
index ef91b8a29d6..e296fb19fc3 100644
--- a/src/HotChocolate/Core/src/Types/Types/ObjectTypeExtension~1.cs
+++ b/src/HotChocolate/Core/src/Types/Types/ObjectTypeExtension~1.cs
@@ -46,14 +46,6 @@ public ObjectTypeExtension(Action> configure)
_configure!(descriptor);
_configure = null;
- // if the object type is inferred from a runtime time we will bind fields implicitly
- // even if the schema building option are set to bind explicitly by default;
- // otherwise we would end up with types that have no fields.
- if (context.IsInferred)
- {
- descriptor.BindFieldsImplicitly();
- }
-
return descriptor.CreateDefinition();
}
diff --git a/src/HotChocolate/Core/src/Types/Types/ObjectType~1.cs b/src/HotChocolate/Core/src/Types/Types/ObjectType~1.cs
index b1a31ff971a..442204f3d42 100644
--- a/src/HotChocolate/Core/src/Types/Types/ObjectType~1.cs
+++ b/src/HotChocolate/Core/src/Types/Types/ObjectType~1.cs
@@ -2,24 +2,29 @@
using HotChocolate.Configuration;
using HotChocolate.Types.Descriptors;
using HotChocolate.Types.Descriptors.Definitions;
+using HotChocolate.Types.Helpers;
#nullable enable
namespace HotChocolate.Types;
///
+///
/// GraphQL operations are hierarchical and composed, describing a tree of information.
/// While Scalar types describe the leaf values of these hierarchical operations,
/// Objects describe the intermediate levels.
-///
+///
+///
/// GraphQL Objects represent a list of named fields, each of which yield a value of a
/// specific type. Object values should be serialized as ordered maps, where the selected
/// field names (or aliases) are the keys and the result of evaluating the field is the value,
/// ordered by the order in which they appear in the selection set.
-///
+///
+///
/// All fields defined within an Object type must not have a name which begins
/// with "__" (two underscores), as this is used exclusively by
/// GraphQL’s introspection system.
+///
///
public class ObjectType : ObjectType
{
@@ -45,14 +50,6 @@ public ObjectType(Action> configure)
_configure!(descriptor);
_configure = null;
- // if the object type is inferred from a runtime time we will bind fields implicitly
- // even if the schema building option are set to bind explicitly by default;
- // otherwise we would end up with types that have no fields.
- if (context.IsInferred)
- {
- descriptor.BindFieldsImplicitly();
- }
-
return descriptor.CreateDefinition();
}
diff --git a/src/HotChocolate/Core/src/Types/Types/UnionType~1.cs b/src/HotChocolate/Core/src/Types/Types/UnionType~1.cs
index 27dc9f52619..0c852953a22 100644
--- a/src/HotChocolate/Core/src/Types/Types/UnionType~1.cs
+++ b/src/HotChocolate/Core/src/Types/Types/UnionType~1.cs
@@ -8,8 +8,7 @@
namespace HotChocolate.Types;
-public class UnionType
- : UnionType
+public class UnionType : UnionType
{
private Action? _configure;
diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/BindingBehaviorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/BindingBehaviorTests.cs
new file mode 100644
index 00000000000..b39bfd6a1a3
--- /dev/null
+++ b/src/HotChocolate/Core/test/Types.Tests/Types/BindingBehaviorTests.cs
@@ -0,0 +1,155 @@
+using System.Threading.Tasks;
+using CookieCrumble;
+using HotChocolate.Execution;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace HotChocolate.Types;
+
+public class BindingBehaviorTests
+{
+ [Fact]
+ public async Task BindingBehavior_Explicit_All_Attributes()
+ {
+ var schema =
+ await new ServiceCollection()
+ .AddGraphQL()
+ .AddQueryType()
+ .AddType()
+ .ModifyOptions(o => o.DefaultBindingBehavior = BindingBehavior.Explicit)
+ .BuildSchemaAsync();
+
+ schema.MatchInlineSnapshot(
+ """
+ schema {
+ query: Query
+ }
+
+ type Book1 {
+ title: String
+ category: BookCategory1!
+ }
+
+ type Query {
+ books: Book1
+ }
+
+ enum BookCategory1 {
+ A
+ B
+ C
+ }
+ """);
+ }
+
+ [QueryType]
+ public class Query1
+ {
+ public Book1 GetBooks() => new("Abc", BookCategory1.B);
+ }
+
+ [ObjectType]
+ public record Book1(string Title, BookCategory1 Category);
+
+ [EnumType]
+ public enum BookCategory1
+ {
+ A,
+ B,
+ C
+ }
+
+ [Fact]
+ public async Task BindingBehavior_Explicit_Enum_Missing_Attribute()
+ {
+ async Task Error() =>
+ await new ServiceCollection()
+ .AddGraphQL()
+ .AddQueryType()
+ .AddType()
+ .ModifyOptions(o => o.DefaultBindingBehavior = BindingBehavior.Explicit)
+ .BuildSchemaAsync();
+
+ var error = await Assert.ThrowsAsync(Error);
+
+ error.Message.MatchInlineSnapshot(
+ """
+ For more details look at the `Errors` property.
+
+ 1. The enum type `BookCategory2` has no values. (HotChocolate.Types.EnumType)
+
+ """);
+ }
+
+ [QueryType]
+ public class Query2
+ {
+ public Book2 GetBooks() => new("Abc", BookCategory2.B);
+ }
+
+ [ObjectType]
+ public record Book2(string Title, BookCategory2 Category);
+
+ public enum BookCategory2
+ {
+ A,
+ B,
+ C
+ }
+
+ [Fact]
+ public async Task BindingBehavior_Explicit_Enum_Bound_With_Fluent()
+ {
+ var schema =
+ await new ServiceCollection()
+ .AddGraphQL()
+ .AddQueryType()
+ .AddType()
+ .AddType()
+ .ModifyOptions(o => o.DefaultBindingBehavior = BindingBehavior.Explicit)
+ .BuildSchemaAsync();
+
+ schema.MatchInlineSnapshot(
+ """
+ schema {
+ query: Query
+ }
+
+ type Book3 {
+ title: String
+ category: BookCategory3!
+ }
+
+ type Query {
+ books: Book3
+ }
+
+ enum BookCategory3 {
+ A
+ }
+ """);
+ }
+
+ [QueryType]
+ public class Query3
+ {
+ public Book3 GetBooks() => new("Abc", BookCategory3.B);
+ }
+
+ [ObjectType]
+ public record Book3(string Title, BookCategory3 Category);
+
+ public enum BookCategory3
+ {
+ A,
+ B,
+ C
+ }
+
+ public class BookCategory3Type : EnumType
+ {
+ protected override void Configure(IEnumTypeDescriptor descriptor)
+ {
+ descriptor.Value(BookCategory3.A);
+ }
+ }
+}