Avoid `InvalidOperationException` when serializing `SerializableError`
- #8055 - provide unique name (`<Empty-Key>`) for XML elements that would otherwise be nameless nits: - remove now-useless Mono special case in updated test class - extend updated tests to involve square brackets as well as empty keys
This commit is contained in:
parent
f31ab716ee
commit
498fa2d72f
|
|
@ -14,6 +14,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
[XmlRoot("Error")]
|
||||
public sealed class SerializableErrorWrapper : IXmlSerializable, IUnwrappable
|
||||
{
|
||||
// Element name used when ModelStateEntry's Key is empty. Dash in element name should avoid collisions with
|
||||
// other ModelState entries because the character is not legal in an expression name.
|
||||
private static readonly string EmptyKey = "MVC-Empty";
|
||||
|
||||
// Note: XmlSerializer requires to have default constructor
|
||||
public SerializableErrorWrapper()
|
||||
{
|
||||
|
|
@ -63,6 +67,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
{
|
||||
var key = XmlConvert.DecodeName(reader.LocalName);
|
||||
var value = reader.ReadInnerXml();
|
||||
if (string.Equals(EmptyKey, key, StringComparison.Ordinal))
|
||||
{
|
||||
key = string.Empty;
|
||||
}
|
||||
|
||||
SerializableError.Add(key, value);
|
||||
reader.MoveToContent();
|
||||
|
|
@ -81,6 +89,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
{
|
||||
var key = keyValuePair.Key;
|
||||
var value = keyValuePair.Value;
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
key = EmptyKey;
|
||||
}
|
||||
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(key));
|
||||
if (value != null)
|
||||
{
|
||||
|
|
@ -102,4 +115,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
return SerializableError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Runtime.Serialization;
|
|||
using System.Text;
|
||||
using System.Xml;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||
|
|
@ -28,8 +27,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
public void WrappedSerializableErrorInstance_ReturnedFromProperty()
|
||||
{
|
||||
// Arrange
|
||||
var serializableError = new SerializableError();
|
||||
serializableError.Add("key1", "key1-error");
|
||||
var serializableError = new SerializableError
|
||||
{
|
||||
{ "key1", "key1-error" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var wrapper = new SerializableErrorWrapper(serializableError);
|
||||
|
|
@ -57,7 +58,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
{
|
||||
// Arrange
|
||||
var serializableErrorXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Error><key1>Test Error 1 Test Error 2</key1><key2>Test Error 3</key2></Error>";
|
||||
"<Error><MVC-Empty>Test error 0</MVC-Empty>" +
|
||||
"<key1>Test Error 1 Test Error 2</key1>" +
|
||||
"<key2>Test Error 3</key2>" +
|
||||
"<list_x005B_3_x005D_.key3>Test Error 4</list_x005B_3_x005D_.key3></Error>";
|
||||
var serializer = new DataContractSerializer(typeof(SerializableErrorWrapper));
|
||||
|
||||
// Act
|
||||
|
|
@ -66,8 +70,28 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
var errors = wrapper.SerializableError;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Test Error 1 Test Error 2", errors["key1"]);
|
||||
Assert.Equal("Test Error 3", errors["key2"]);
|
||||
Assert.Collection(
|
||||
errors,
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal(string.Empty, kvp.Key);
|
||||
Assert.Equal("Test error 0", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("key1", kvp.Key);
|
||||
Assert.Equal("Test Error 1 Test Error 2", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("key2", kvp.Key);
|
||||
Assert.Equal("Test Error 3", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("list[3].key3", kvp.Key);
|
||||
Assert.Equal("Test Error 4", kvp.Value);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -75,11 +99,18 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError(string.Empty, "Test error 0");
|
||||
modelState.AddModelError("key1", "Test Error 1");
|
||||
modelState.AddModelError("key1", "Test Error 2");
|
||||
modelState.AddModelError("key2", "Test Error 3");
|
||||
modelState.AddModelError("list[3].key3", "Test Error 4");
|
||||
var serializableError = new SerializableError(modelState);
|
||||
var outputStream = new MemoryStream();
|
||||
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Error><MVC-Empty>Test error 0</MVC-Empty>" +
|
||||
"<key1>Test Error 1 Test Error 2</key1>" +
|
||||
"<key2>Test Error 3</key2>" +
|
||||
"<list_x005B_3_x005D_.key3>Test Error 4</list_x005B_3_x005D_.key3></Error>";
|
||||
|
||||
// Act
|
||||
using (var xmlWriter = XmlWriter.Create(outputStream))
|
||||
|
|
@ -91,15 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
var res = new StreamReader(outputStream, Encoding.UTF8).ReadToEnd();
|
||||
|
||||
// Assert
|
||||
var expectedContent =
|
||||
TestPlatformHelper.IsMono ?
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?><Error xmlns:i=\"" +
|
||||
"http://www.w3.org/2001/XMLSchema-instance\"><key1>Test Error 1 Test Error 2</key1>" +
|
||||
"<key2>Test Error 3</key2></Error>" :
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Error><key1>Test Error 1 Test Error 2</key1><key2>Test Error 3</key2></Error>";
|
||||
|
||||
Assert.Equal(expectedContent, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue