[Fixes #5413] JsonOutputFormatter adds all closing brackets when exceptions are thrown
This commit is contained in:
parent
b22326323a
commit
c18f0780c1
|
|
@ -33,8 +33,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
/// <param name="options">The <see cref="IOptions{MvcJsonOptions}"/>.</param>
|
/// <param name="options">The <see cref="IOptions{MvcJsonOptions}"/>.</param>
|
||||||
/// <param name="charPool">The <see cref="ArrayPool{Char}"/> for creating <see cref="T:char[]"/> buffers.</param>
|
/// <param name="charPool">The <see cref="ArrayPool{Char}"/> for creating <see cref="T:char[]"/> buffers.</param>
|
||||||
public JsonResultExecutor(
|
public JsonResultExecutor(
|
||||||
IHttpResponseStreamWriterFactory writerFactory,
|
IHttpResponseStreamWriterFactory writerFactory,
|
||||||
ILogger<JsonResultExecutor> logger,
|
ILogger<JsonResultExecutor> logger,
|
||||||
IOptions<MvcJsonOptions> options,
|
IOptions<MvcJsonOptions> options,
|
||||||
ArrayPool<char> charPool)
|
ArrayPool<char> charPool)
|
||||||
{
|
{
|
||||||
|
|
@ -124,6 +124,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
{
|
{
|
||||||
jsonWriter.ArrayPool = _charPool;
|
jsonWriter.ArrayPool = _charPool;
|
||||||
jsonWriter.CloseOutput = false;
|
jsonWriter.CloseOutput = false;
|
||||||
|
jsonWriter.AutoCompleteOnClose = false;
|
||||||
|
|
||||||
var jsonSerializer = JsonSerializer.Create(serializerSettings);
|
var jsonSerializer = JsonSerializer.Create(serializerSettings);
|
||||||
jsonSerializer.Serialize(jsonWriter, result.Value);
|
jsonSerializer.Serialize(jsonWriter, result.Value);
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
ArrayPool = _charPool,
|
ArrayPool = _charPool,
|
||||||
CloseOutput = false,
|
CloseOutput = false,
|
||||||
|
AutoCompleteOnClose = false
|
||||||
};
|
};
|
||||||
|
|
||||||
return jsonWriter;
|
return jsonWriter;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -156,6 +157,31 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
Assert.Equal("application/json; charset=utf-8", context.HttpContext.Response.ContentType);
|
Assert.Equal("application/json; charset=utf-8", context.HttpContext.Response.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ExecuteAsync_ErrorDuringSerialization_DoesNotCloseTheBrackets()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = Encoding.UTF8.GetBytes("{\"name\":\"Robert\"");
|
||||||
|
var context = GetActionContext();
|
||||||
|
var result = new JsonResult(new ModelWithSerializationError());
|
||||||
|
var executor = CreateExcutor();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await executor.ExecuteAsync(context, result);
|
||||||
|
}
|
||||||
|
catch (JsonSerializationException serializerException)
|
||||||
|
{
|
||||||
|
var expectedException = Assert.IsType<NotImplementedException>(serializerException.InnerException);
|
||||||
|
Assert.Equal("Property Age has not been implemented", expectedException.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var written = GetWrittenBytes(context.HttpContext);
|
||||||
|
Assert.Equal(expected, written);
|
||||||
|
}
|
||||||
|
|
||||||
private static JsonResultExecutor CreateExcutor()
|
private static JsonResultExecutor CreateExcutor()
|
||||||
{
|
{
|
||||||
return new JsonResultExecutor(
|
return new JsonResultExecutor(
|
||||||
|
|
@ -188,5 +214,17 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
context.Response.Body.Seek(0, SeekOrigin.Begin);
|
context.Response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
return Assert.IsType<MemoryStream>(context.Response.Body).ToArray();
|
return Assert.IsType<MemoryStream>(context.Response.Body).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ModelWithSerializationError
|
||||||
|
{
|
||||||
|
public string Name { get; } = "Robert";
|
||||||
|
public int Age
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Property {nameof(Age)} has not been implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{ "This is a test 激光這兩個字是甚麼意思 string written using shift_jis", "shift_jis", false },
|
{ "This is a test 激光這兩個字是甚麼意思 string written using shift_jis", "shift_jis", false },
|
||||||
#elif NETCOREAPP2_0
|
#elif NETCOREAPP2_0
|
||||||
#else
|
#else
|
||||||
#error target frameworks needs to be updated.
|
#error target frameworks needs to be updated.
|
||||||
#endif
|
#endif
|
||||||
{ "This is a test æøå string written using iso-8859-1", "iso-8859-1", false },
|
{ "This is a test æøå string written using iso-8859-1", "iso-8859-1", false },
|
||||||
};
|
};
|
||||||
|
|
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
#elif NETCOREAPP2_0
|
#elif NETCOREAPP2_0
|
||||||
#else
|
#else
|
||||||
#error target frameworks needs to be updated.
|
#error target frameworks needs to be updated.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
@ -369,6 +369,38 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
Assert.Equal(expectedData, actualData);
|
Assert.Equal(expectedData, actualData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ErrorDuringSerialization_DoesNotCloseTheBrackets()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedOutput = "{\"name\":\"Robert\"";
|
||||||
|
var outputFormatterContext = GetOutputFormatterContext(
|
||||||
|
new ModelWithSerializationError(),
|
||||||
|
typeof(ModelWithSerializationError));
|
||||||
|
var serializerSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
|
||||||
|
var jsonFormatter = new JsonOutputFormatter(serializerSettings, ArrayPool<char>.Shared);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
catch (JsonSerializationException serializerException)
|
||||||
|
{
|
||||||
|
var expectedException = Assert.IsType<NotImplementedException>(serializerException.InnerException);
|
||||||
|
Assert.Equal("Property Age has not been implemented", expectedException.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||||
|
|
||||||
|
Assert.NotNull(body);
|
||||||
|
body.Position = 0;
|
||||||
|
|
||||||
|
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
|
||||||
|
Assert.Equal(expectedOutput, content);
|
||||||
|
}
|
||||||
|
|
||||||
private static Encoding CreateOrGetSupportedEncoding(
|
private static Encoding CreateOrGetSupportedEncoding(
|
||||||
JsonOutputFormatter formatter,
|
JsonOutputFormatter formatter,
|
||||||
string encodingAsString,
|
string encodingAsString,
|
||||||
|
|
@ -467,5 +499,17 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
public string FullName { get; set; }
|
public string FullName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ModelWithSerializationError
|
||||||
|
{
|
||||||
|
public string Name { get; } = "Robert";
|
||||||
|
public int Age
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Property {nameof(Age)} has not been implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue