Skip to content

Commit be7dfa3

Browse files
authored
Use InputFormatterException for another case (#6316)
- #4917 nits: - test `ExceptionPolicy` logic in an input formatter - remove old Mono workarounds in `SerializaterErrorTests` - fix typo in `SerializableErrorTests` (not using theory data)
1 parent c2df506 commit be7dfa3

File tree

3 files changed

+88
-37
lines changed

3 files changed

+88
-37
lines changed

src/Mvc/src/Microsoft.AspNetCore.Mvc.Formatters.Xml/XmlSerializerInputFormatter.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,19 @@ public override async Task<InputFormatterResult> ReadRequestBodyAsync(
159159
}
160160
// XmlSerializer wraps actual exceptions (like FormatException or XmlException) into an InvalidOperationException
161161
// https://github.com/dotnet/corefx/blob/master/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs#L652
162-
catch (InvalidOperationException exception) when (exception.InnerException is FormatException || exception.InnerException is XmlException)
162+
catch (InvalidOperationException exception) when (exception.InnerException != null &&
163+
exception.InnerException.InnerException == null &&
164+
string.Equals("Microsoft.GeneratedCode", exception.InnerException.Source, StringComparison.InvariantCulture))
163165
{
164-
throw new InputFormatterException(Resources.ErrorDeserializingInputData, exception);
166+
// Know this was an XML parsing error because the inner Exception was thrown in the (generated)
167+
// assembly the XmlSerializer uses for parsing. The problem did not arise lower in the stack i.e. it's
168+
// not (for example) an out-of-memory condition.
169+
throw new InputFormatterException(Resources.ErrorDeserializingInputData, exception.InnerException);
170+
}
171+
catch (InvalidOperationException exception) when (exception.InnerException is FormatException ||
172+
exception.InnerException is XmlException)
173+
{
174+
throw new InputFormatterException(Resources.ErrorDeserializingInputData, exception.InnerException);
165175
}
166176
}
167177

src/Mvc/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/BodyModelBinderTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,6 @@ public DerivedXmlDataContractSerializerInputFormatter(bool throwNonInputFormatte
839839
_throwNonInputFormatterException = throwNonInputFormatterException;
840840
}
841841

842-
public override InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.AllExceptions;
843-
844842
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
845843
{
846844
if (_throwNonInputFormatterException)

src/Mvc/test/Microsoft.AspNetCore.Mvc.FunctionalTests/SerializableErrorTests.cs

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
using System.Text;
88
using System.Threading.Tasks;
99
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
10-
using Microsoft.AspNetCore.Testing;
11-
using Microsoft.AspNetCore.Testing.xunit;
1210
using Xunit;
1311

1412
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
@@ -22,22 +20,15 @@ public SerializableErrorTests(MvcTestFixture<XmlFormattersWebSite.Startup> fixtu
2220

2321
public HttpClient Client { get; }
2422

25-
public static TheoryData AcceptHeadersData
23+
public static TheoryData<string> AcceptHeadersData
2624
{
2725
get
2826
{
29-
var data = new TheoryData<string>
27+
return new TheoryData<string>
3028
{
29+
"application/xml-dcs",
3130
"application/xml-xmlser"
3231
};
33-
34-
// Mono issue - https://github.com/aspnet/External/issues/18
35-
if (!TestPlatformHelper.IsMono)
36-
{
37-
data.Add("application/xml-dcs");
38-
}
39-
40-
return data;
4132
}
4233
}
4334

@@ -62,19 +53,16 @@ public async Task ModelStateErrors_AreSerialized(string acceptHeader)
6253
XmlAssert.Equal(expectedXml, responseData);
6354
}
6455

65-
[ConditionalTheory]
66-
// Mono issue - https://github.com/aspnet/External/issues/18
67-
// XmlSerializer test is disabled Mono.Xml2.XmlTextReader.ReadText is unable to read the XML.
68-
// This is fixed in mono 4.3.0.
69-
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
70-
[InlineData("application/xml-xmlser")]
71-
[InlineData("application/xml-dcs")]
56+
[Theory]
57+
[MemberData(nameof(AcceptHeadersData))]
7258
public async Task PostedSerializableError_IsBound(string acceptHeader)
7359
{
7460
// Arrange
7561
var expectedXml = "<Error><key1>key1-error</key1><key2>The input was not valid.</key2></Error>";
76-
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/LogErrors");
77-
request.Content = new StringContent(expectedXml, Encoding.UTF8, acceptHeader);
62+
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/LogErrors")
63+
{
64+
Content = new StringContent(expectedXml, Encoding.UTF8, acceptHeader)
65+
};
7866
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptHeader));
7967

8068
// Act
@@ -89,25 +77,80 @@ public async Task PostedSerializableError_IsBound(string acceptHeader)
8977
XmlAssert.Equal(expectedXml, responseData);
9078
}
9179

92-
[ConditionalTheory]
93-
// Mono issue - https://github.com/aspnet/External/issues/18
94-
// XmlSerializer test is disabled Mono.Xml2.XmlTextReader.ReadText is unable to read the XML.
95-
// This is fixed in mono 4.3.0.
96-
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
97-
[InlineData("application/xml-xmlser")]
98-
[InlineData("application/xml-dcs")]
99-
public async Task IsReturnedInExpectedFormat(string acceptHeader)
80+
public static TheoryData<string, string> InvalidInputAndHeadersData
81+
{
82+
get
83+
{
84+
return new TheoryData<string, string>
85+
{
86+
{
87+
"application/xml-dcs",
88+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
89+
"<Employee xmlns =\"http://schemas.datacontract.org/2004/07/XmlFormattersWebSite.Models\">" +
90+
"<Id>2</Id><Name>foo</Name></Employee>"
91+
},
92+
{
93+
"application/xml-xmlser",
94+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
95+
"<Employee>" +
96+
"<Id>2</Id><Name>foo</Name></Employee>"
97+
},
98+
};
99+
}
100+
}
101+
102+
[Theory]
103+
[MemberData(nameof(InvalidInputAndHeadersData))]
104+
public async Task IsReturnedInExpectedFormat(string acceptHeader, string inputXml)
100105
{
101106
// Arrange
102-
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
103-
"<Employee xmlns=\"http://schemas.datacontract.org/2004/07/XmlFormattersWebSite.Models\">" +
104-
"<Id>2</Id><Name>foo</Name></Employee>";
105107
var expected = "<Error><Id>The field Id must be between 10 and 100.</Id>" +
106108
"<Name>The field Name must be a string or array type with a minimum " +
107109
"length of '15'.</Name></Error>";
108110
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee");
109111
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(acceptHeader));
110-
request.Content = new StringContent(input, Encoding.UTF8, "application/xml-dcs");
112+
request.Content = new StringContent(inputXml, Encoding.UTF8, acceptHeader);
113+
114+
// Act
115+
var response = await Client.SendAsync(request);
116+
117+
// Assert
118+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
119+
var responseData = await response.Content.ReadAsStringAsync();
120+
XmlAssert.Equal(expected, responseData);
121+
}
122+
123+
public static TheoryData<string, string> IncorrectTopLevelInputAndHeadersData
124+
{
125+
get
126+
{
127+
return new TheoryData<string, string>
128+
{
129+
{
130+
"application/xml-dcs",
131+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
132+
"<Employees xmlns =\"http://schemas.datacontract.org/2004/07/XmlFormattersWebSite.Models\">" +
133+
"<Id>2</Id><Name>foo</Name></Employee>"
134+
},
135+
{
136+
"application/xml-xmlser",
137+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
138+
"<Employees>" +
139+
"<Id>2</Id><Name>foo</Name></Employee>"
140+
},
141+
};
142+
}
143+
}
144+
145+
[Theory]
146+
[MemberData(nameof(IncorrectTopLevelInputAndHeadersData))]
147+
public async Task IncorrectTopLevelElement_ReturnsExpectedError(string acceptHeader, string inputXml)
148+
{
149+
// Arrange
150+
var expected = "<Error><MVC-Empty>An error occurred while deserializing input data.</MVC-Empty></Error>";
151+
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee");
152+
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(acceptHeader));
153+
request.Content = new StringContent(inputXml, Encoding.UTF8, acceptHeader);
111154

112155
// Act
113156
var response = await Client.SendAsync(request);

0 commit comments

Comments
 (0)