Description
Given JSON content like "[{\"It's a key\": 1234556}]"
which is deserialized as IDictionary<string, short>
(the value is too big for a short making this an error), NewtonsoftJsonInputFormatter
adds an entry to the ModelStateDictionary
with the key "['It\\'s a key'].It's a key"
instead of ['It\\'s a key']
as expected.
[Fact]
public virtual async Task JsonFormatter_EscapedKeys_SingleQuote()
{
var expectedKey = JsonFormatter_EscapedKeys_SingleQuote_Expected;
// Arrange
var content = "{\"It's a key\": 1234556}";
var formatter = GetInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(content);
var httpContext = GetHttpContext(contentBytes);
var formatterContext = CreateInputFormatterContext(
typeof(IDictionary<string, short>), httpContext);
// Act
var result = await formatter.ReadAsync(formatterContext);
// Assert
Assert.True(result.HasError);
Assert.Collection(
formatterContext.ModelState.OrderBy(k => k.Key),
kvp =>
{
// This fails with Expected: ['It\'s a key'], Actual: ['It\'s a key'].It's a key
Assert.Equal("['It\\'s a key']", kvp.Key);
});
}
This is caused by logic in NewtonsoftJsonInputFormatter
's ErrorHandler
that appends the ErrorContext.Member
to the ErrorContext.Path
when the Path
doesn't already end with Member
in order to better report missing required properties.
aspnetcore/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs
Lines 238 to 263 in 28ecab6
ErrorContext.Path
escapes the '
, but ErrorContext.Member
doesn't meaning the !path.EndsWith()
checks don't cover this scenario. We could scan ErrorContext.Member
for any '
characters and manually escape it before doing the !path.EndsWith()
checks, but that feels like playing whac-a-mole. I'm guessing there are even more edge cases the !path.EndsWith()
checks don't cover.
I really want to get rid of the addMember
logic altogether and have Json.NET either give us the path we want to begin with or expose an ErrorContext.ErrorType
so we only do the addMember
logic for missing required properties where we know the member is never in the path. The latter option was proposed a while back but never implemennted in Json.NET. See JamesNK/Newtonsoft.Json#1903
See #39058 (comment) for more context about this issue.