Replaced ByteArrayType with Base64StringType and deprecated the former#9105
Replaced ByteArrayType with Base64StringType and deprecated the former#9105
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces the Base64String scalar as the preferred GraphQL representation for .NET byte[], updates default runtime mapping accordingly, and deprecates the legacy ByteArray scalar/type across Hot Chocolate + Strawberry Shake, along with updating docs and test snapshots.
Changes:
- Added
Base64StringTypeand mappedbyte[]toBase64Stringby default; markedByteArrayTypeobsolete. - Updated Strawberry Shake code generation to treat
Base64Stringas a built-in scalar. - Updated documentation, tests, and snapshots across Hot Chocolate/Adapters/Strawberry Shake to reflect the new scalar name.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| website/src/docs/strawberryshake/v16/scalars.md | Updates Strawberry Shake scalar docs to list Base64String (and adjusts note formatting). |
| website/src/docs/hotchocolate/v16/migrating/migrate-from-15-to-16.md | Adds migration guidance + deprecation note for ByteArray → Base64String. |
| website/src/docs/hotchocolate/v16/defining-a-schema/scalars.md | Updates Hot Chocolate scalar docs and runtime binding example to Base64StringType. |
| src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/snapshots/ScalarGeneratorTests.Base64String_ScalarType.snap | Adds snapshot for generated client code using Base64String. |
| src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/ScalarGeneratorTests.cs | Adds a new codegen test for the Base64String scalar. |
| src/StrawberryShake/CodeGeneration/src/CodeGeneration/Utilities/SchemaHelper.cs | Registers Base64String as a default scalar mapping (byte[]). |
| src/StrawberryShake/CodeGeneration/src/CodeGeneration/BuiltInScalarNames.cs | Adds Base64String to Strawberry Shake codegen built-in scalar name set. |
| src/StrawberryShake/Client/src/Core/Serialization/BuiltInScalarNames.cs | Adds Base64String constant and reorders built-in scalar name constants. |
| src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteArrayTypeTests.cs | Suppresses obsolete warnings for ByteArrayType tests. |
| src/HotChocolate/Core/test/Types.Tests/Types/Scalars/Base64StringTypeTests.cs | Adds test coverage for the new Base64StringType. |
| src/HotChocolate/Core/test/Types.Tests/Configuration/SchemaTypeDiscoveryTests.cs | Updates scalar discovery test expectations to Base64String. |
| src/HotChocolate/Core/test/Types.Json.Tests/snapshots/FromJsonDirectiveTests.MapField_AutomaticScalars.snap | Updates snapshot to include base64String field output. |
| src/HotChocolate/Core/test/Types.Json.Tests/FromJsonDirectiveTests.cs | Updates test schema/query/data to include Base64String. |
| src/HotChocolate/Core/src/Types/Types/Scalars/Scalars.cs | Changes default CLR byte[] mapping to Base64StringType and registers scalar name mapping. |
| src/HotChocolate/Core/src/Types/Types/Scalars/ScalarNames.cs | Adds Base64String scalar name constant and reorders constants. |
| src/HotChocolate/Core/src/Types/Types/Scalars/ByteArrayType.cs | Marks ByteArrayType as obsolete. |
| src/HotChocolate/Core/src/Types/Types/Scalars/Base64StringType.cs | Introduces the new scalar implementation for base64-encoded byte arrays. |
| src/HotChocolate/Core/src/Types/Configuration/TypeLookup.cs | Updates comment examples to reference Base64String. |
| src/HotChocolate/Core/src/Types.Json/JsonObjectTypeExtensions.cs | Updates JSON inference to treat both Base64String and ByteArray similarly. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/TestSchema.cs | Updates OpenAPI adapter test schema types/fields to Base64StringType. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/OpenApiTestBase.cs | Updates OpenAPI adapter test query selections to include base64String. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/OpenApi/snapshots/OpenApiIntegrationTestBase.OpenApi_Includes_Initial_Routes_NET10_0_Fusion.json | Updates OpenAPI snapshot output to include base64String schema. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/OpenApi/snapshots/OpenApiIntegrationTestBase.OpenApi_Includes_Initial_Routes_NET10_0.json | Updates OpenAPI snapshot output to include base64String schema/pattern. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/snapshots/HttpEndpointIntegrationTestBase.Http_Post_Complex_Object.snap | Updates endpoint response snapshot to include base64String field. |
| src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/HttpEndpointIntegrationTestBase.cs | Updates endpoint request payload used in tests to include base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNullableVariables_CreatesCorrectSchema_Output.json | Updates MCP schema snapshot to include base64String (nullable). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNullableVariables_CreatesCorrectSchema_Input.json | Updates MCP schema snapshot inputs to include base64String (nullable). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNonNullableVariables_CreatesCorrectSchema_Output.json | Updates MCP schema snapshot to include base64String (non-null). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNonNullableVariables_CreatesCorrectSchema_Input.json | Updates MCP schema snapshot inputs to include base64String (non-null). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithDefaultedVariables_CreatesCorrectSchema_Output.json | Updates MCP schema snapshot to include base64String (defaulted). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithDefaultedVariables_CreatesCorrectSchema_Input.json | Updates MCP schema snapshot inputs to include base64String (defaulted). |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/IntegrationTestBase.CallTool_GetWithNullableVariables_ReturnsExpectedResult.json | Updates integration result snapshot to include base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/IntegrationTestBase.CallTool_GetWithNonNullableVariables_ReturnsExpectedResult.json | Updates integration result snapshot to include base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/IntegrationTestBase.CallTool_GetWithDefaultedVariables_ReturnsExpectedResult.json | Updates integration result snapshot to include base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/resources/GetWithNullableVariables.graphql | Updates MCP resource query to use Base64String variable/field. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/resources/GetWithNonNullableVariables.graphql | Updates MCP resource query to use Base64String variable/field. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/resources/GetWithDefaultedVariables.graphql | Updates MCP resource query defaults to use Base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/TestSchema.cs | Updates MCP test schema runtime types/records to use Base64StringType. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/IntegrationTestBase.cs | Updates tool invocation variable dictionaries to use base64String. |
| src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/Extensions/TypeExtensionsTests.cs | Updates JSON-schema pattern tests to use Base64StringType. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🚀 Fusion Gateway Performance ResultsSimple Composite QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
}
}
}
}Deep Recursion QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
users {
...User
reviews {
...Review
product {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}
}
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}Variable Batching ThroughputConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query query TestQuery_8f7a46ce_2(
$__fusion_1_upc: ID!
$__fusion_2_price: Long!
$__fusion_2_weight: Long!
) {
productByUpc(upc: $__fusion_1_upc) {
inStock
shippingEstimate(weight: $__fusion_2_weight, price: $__fusion_2_price)
}
}Variables (5 sets batched in single request) [
{ "__fusion_1_upc": "1", "__fusion_2_price": 899, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "2", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 },
{ "__fusion_1_upc": "3", "__fusion_2_price": 15, "__fusion_2_weight": 20 },
{ "__fusion_1_upc": "4", "__fusion_2_price": 499, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "5", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 }
]No baseline data available for comparison. Run 21861037883 • Commit c518b76 • Tue, 10 Feb 2026 10:41:41 GMT |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private readonly global::StrawberryShake.Serialization.ILeafValueParser<global::System.Byte[], global::System.Byte[]> _base64StringParser; | ||
| public GetAttachmentBuilder(global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityIdSerializer idSerializer, global::StrawberryShake.IOperationResultDataFactory<global::Foo.Bar.IGetAttachmentResult> resultDataFactory, global::StrawberryShake.Serialization.ISerializerResolver serializerResolver) | ||
| { | ||
| _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); | ||
| _idSerializer = idSerializer ?? throw new global::System.ArgumentNullException(nameof(idSerializer)); | ||
| ResultDataFactory = resultDataFactory ?? throw new global::System.ArgumentNullException(nameof(resultDataFactory)); | ||
| _base64StringParser = serializerResolver.GetLeafValueParser<global::System.Byte[], global::System.Byte[]>("Base64String") ?? throw new global::System.ArgumentException("No serializer for type `Base64String` found."); | ||
| } |
There was a problem hiding this comment.
In this generated snapshot, the result builder resolves a leaf value parser for type name "Base64String", but the DI setup later only registers ByteArraySerializer with its default type name ("ByteArray"). Unless ByteArraySerializer is also registered with type name "Base64String" (or a dedicated serializer exists), this client will throw at runtime when constructing the builder.
| TryAddLeafType( | ||
| leafTypes, | ||
| typeName: ScalarNames.Base64String, | ||
| runtimeType: TypeNames.ByteArray, | ||
| serializationType: TypeNames.ByteArray); |
There was a problem hiding this comment.
Base64String is now added as a default scalar mapping to byte[], but StrawberryShake’s built-in ByteArraySerializer registers under the ByteArray type name by default. The generated client code will request a leaf value parser for type name "Base64String" and can throw at runtime ("No serializer for type Base64String found.") unless a serializer is registered for that name. Consider adding a dedicated Base64StringSerializer (or registering ByteArraySerializer with typeName Base64String) in the DI/codegen path so both scalar names resolve correctly.
🚀 Fusion Gateway Performance ResultsSimple Composite QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
}
}
}
}Deep Recursion QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
users {
...User
reviews {
...Review
product {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}
}
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}Variable Batching ThroughputConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query query TestQuery_8f7a46ce_2(
$__fusion_1_upc: ID!
$__fusion_2_price: Long!
$__fusion_2_weight: Long!
) {
productByUpc(upc: $__fusion_1_upc) {
inStock
shippingEstimate(weight: $__fusion_2_weight, price: $__fusion_2_price)
}
}Variables (5 sets batched in single request) [
{ "__fusion_1_upc": "1", "__fusion_2_price": 899, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "2", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 },
{ "__fusion_1_upc": "3", "__fusion_2_price": 15, "__fusion_2_weight": 20 },
{ "__fusion_1_upc": "4", "__fusion_2_price": 499, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "5", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 }
]No baseline data available for comparison. Run 21861931922 • Commit 7d10f68 • Tue, 10 Feb 2026 11:09:24 GMT |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 145 out of 176 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🚀 Fusion Gateway Performance ResultsSimple Composite QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
}
}
}
}Deep Recursion QueryConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query fragment User on User {
id
username
name
}
fragment Review on Review {
id
body
}
fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}
query TestQuery {
users {
...User
reviews {
...Review
product {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}
}
topProducts(first: 5) {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}Variable Batching ThroughputConstant Load (50 VUs)
📊 Response Time Metrics
Ramping Load (0→50→500→50 VUs)
📊 Response Time Metrics
Executed Query query TestQuery_8f7a46ce_2(
$__fusion_1_upc: ID!
$__fusion_2_price: Long!
$__fusion_2_weight: Long!
) {
productByUpc(upc: $__fusion_1_upc) {
inStock
shippingEstimate(weight: $__fusion_2_weight, price: $__fusion_2_price)
}
}Variables (5 sets batched in single request) [
{ "__fusion_1_upc": "1", "__fusion_2_price": 899, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "2", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 },
{ "__fusion_1_upc": "3", "__fusion_2_price": 15, "__fusion_2_weight": 20 },
{ "__fusion_1_upc": "4", "__fusion_2_price": 499, "__fusion_2_weight": 100 },
{ "__fusion_1_upc": "5", "__fusion_2_price": 1299, "__fusion_2_weight": 1000 }
]No baseline data available for comparison. Run 21865584831 • Commit 4a28b8b • Tue, 10 Feb 2026 13:08:35 GMT |
Summary of the changes (Less than 80 chars)