Skip to content

Conversation

Copy link

Copilot AI commented Oct 12, 2025

Overview

This PR addresses a breaking change in C# 14 (.NET 10) related to JsonSerializer.Deserialize method overload resolution. Starting with .NET 10, new overloads accepting ReadOnlySpan<byte> are available, which can cause ambiguity errors when the compiler cannot determine which overload to use.

Problem

As documented in the C# 14 compiler breaking changes, code that passes parameters of ambiguous types (like object, var, or nullable types) to JsonSerializer.Deserialize will fail to compile with errors such as:

The call is ambiguous between the following methods or properties: 
'JsonSerializer.Deserialize<TValue>(ReadOnlySpan<byte>, JsonSerializerOptions?)' and 
'JsonSerializer.Deserialize<TValue>(string, JsonSerializerOptions?)'

Solution

Added explicit (string) casts to all JsonSerializer.Deserialize calls where parameters could potentially be ambiguous:

Modified Files

  1. JsonBodyModelBinder.cs

    • Cast jsonPayload parameter to ensure string overload is selected
  2. SettingService.cs

    • Cast setting.Metadata property in both generic (Deserialize<T>) and non-generic calls
    • Metadata is stored as JSON strings in the database
  3. PowerExcelMapper.cs

    • Cast cell.StringCellValue when deserializing JSON data from Excel cells
  4. SessionExtensions.cs

    • Cast value from GetString() which returns string? (nullable string)

Testing

  • ✅ Full solution builds successfully with no warnings or errors
  • ✅ Infrastructure tests pass (69/69)
  • ✅ Web.Common tests pass (11/11)
  • ✅ All other JsonSerializer.Deserialize calls verified as safe

Compatibility

These changes are purely defensive and maintain full backward compatibility with .NET 8 and .NET 9. The explicit casts clarify intent and prepare the codebase for .NET 10 without affecting current functionality.

Related

Fixes #[issue_number] (if applicable)

Thanks to @CancanTang for the early heads-up on this breaking change during .NET 10 smoke testing!

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • ccsca2021.crl.certum.pl
    • Triggering command: dotnet build GrandNode.sln --no-incremental (dns block)
  • ccsca2021.ocsp-certum.com
    • Triggering command: dotnet build GrandNode.sln --no-incremental (dns block)
  • crl.certum.pl
    • Triggering command: dotnet build GrandNode.sln --no-incremental (dns block)
  • subca.ocsp-certum.com
    • Triggering command: dotnet build GrandNode.sln --no-incremental (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>C# 14 breaking change heads up</issue_title>
<issue_description>Hey folks, as part of our smoke testing for .NET 10, we noticed that grandnode2 is impacted by a breaking change in .NET 10 related to https://github.com/dotnet/roslyn/blob/main/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md#spant-and-readonlyspant-overloads-are-applicable-in-more-scenarios-in-c-14-and-newer. When building on dotnet-sdk-10.0.100-rc.2.25474.116, you may encounter errors like:

The call is ambiguous between the following methods or properties: 'JsonSerializer.Deserialize<TValue>(ReadOnlySpan<byte>, JsonSerializerOptions?)' and 'JsonSerializer.Deserialize<TValue>(string, JsonSerializerOptions?)'

This occurs because, starting with .NET 10, the overloads for JsonSerializer.Deserialize were updated, and code that passes a parameter of type 'object' or 'var' (where the type could be either string or byte span) can no longer be resolved automatically by the compiler. This leads to build failures.

To address this, you’ll need to update your code to explicitly cast the parameter to either string or ReadOnlySpan when calling JsonSerializer.Deserialize, as appropriate. For example:

C#
// For string input
JsonSerializer.Deserialize<TValue>((string)input, options);

// For byte input
JsonSerializer.Deserialize<TValue>((ReadOnlySpan<byte>)input, options);
Alternatively, ensure that your code always passes the correct type matching the method signature, or upgrade any dependencies that may be affected by this change.

Please get details from dotnet/sdk#51022 if you need them.

Just wanted to give a heads-up so you can plan for a smooth transition to .NET 10!</issue_description>

Comments on the Issue (you are @copilot in this section)

@KrzysztofPajak @CancanTang Thanks for catching this and for the detailed breakdown! We’ll keep an eye on this and start making the necessary adjustments once .NET 10 is officially out. Really appreciate the early notice — that’ll definitely save us some headaches later 🙂

Fixes #626


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…zer.Deserialize calls

Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copilot AI changed the title [WIP] Fix C# 14 breaking change in grandnode2 Fix C# 14 breaking change - add explicit string casts for JsonSerializer.Deserialize calls Oct 12, 2025
Copilot AI requested a review from KrzysztofPajak October 12, 2025 17:40
Copilot finished work on behalf of KrzysztofPajak October 12, 2025 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants