How it works
JSON distinguishes a numeric token from a string token containing numeric-looking text. Count is an integer property, so the ordinary strict reader rejects the quoted string three. This is not malformed JSON; it is a mismatch between a valid JSON value kind and the expected model contract.
AllowReadingFromString explicitly permits compatible numeric strings. The second call reads the quoted digits and produces the integer three. The final call still rejects the word three because enabling this compatibility option does not turn arbitrary human-language text into a number.
Use this option because an established input schema requires it, not merely to suppress an unexplained error. A producer that sometimes emits numbers and sometimes emits strings may need to be corrected. Accepting both can be appropriate, but the compatibility policy should remain visible and consistently applied.
Numeric range and domain rules still matter. A quoted value outside the integer range cannot become a valid int just because it is a string. A successfully parsed negative count may still violate a business rule. Parsing representation, checking storage range, and validating domain meaning are separate steps.
Practice with a numeric token, a quoted integer, a quoted decimal, an empty string, and an out-of-range integer. Predict which inputs fit the Count property under the strict and permissive options. Then change the property to decimal and explain which outcomes change because the target type changed.
Finally, choose the scope of the option carefully. A global setting changes every compatible numeric member read with those options; an attribute can express a narrower exception when only one legacy field needs it. Tests should include the intentionally supported alternative form and inputs that must remain rejected, preserving a clear boundary around compatibility.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
const string json = """{"Count":"3"}""";
try { JsonSerializer.Deserialize<Counter>(json); }
catch (JsonException) { Console.WriteLine("strict rejected"); }
var options = new JsonSerializerOptions { NumberHandling = JsonNumberHandling.AllowReadingFromString };
Console.WriteLine(JsonSerializer.Deserialize<Counter>(json, options)!.Count);
try { JsonSerializer.Deserialize<Counter>("""{"Count":"three"}""", options); }
catch (JsonException) { Console.WriteLine("text rejected"); }
class Counter { public int Count { get; set; } }
Expected output
strict rejected 3 text rejected
AllowReadingFromString still requires text that represents a compatible number.