In my Startup.ConfigureServices method I have:
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlSerializerInputFormatter());
});
I've also tried:
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
});
My POST method's signature looks like:
[HttpPost("xunit")]
public IActionResult PostXunitResults([FromBody] XunitResult results)
XunitResult looks like:
[Serializable]
[XmlRoot("assemblies")]
public class XunitResult
{
[XmlIgnore]
public const string MimeType = "application/xml";
[XmlAttribute("timestamp")]
public string Timestamp { get; set; }
[XmlElement("assembly")]
public List<Assembly> Assemblies { get; set; }
}
[Serializable]
[XmlType("assembly")]
public class Assembly
{
...
With this setup I can run tests to check that my model deserializes the XML correctly:
[Fact]
public void WhenYouDeserializeXunitResultsIntoAnXunitResultsObject_ThenTheObjectIsPopulatedCorrectly()
{
var serializer = new XmlSerializer(typeof(XunitResult));
XunitResult results;
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(_xunitResults)))
{
results = (XunitResult)serializer.Deserialize(stream);
}
results.Assemblies.Should().NotBeNull();
}
... which it does.
When I try to use XunitResult as a [FromBody] argument to the post method, the model is not rendered correctly in Swagger:
- Swagger does not display
XunitResultcorrectly in the example, it renders the root as 'XunitResult' instead of 'assemblies' as defined in theXMLRootAttributeonXunitResult. - Also, the same model does not render the Timestamp property in
XunitResultas an attribute, it renders it as an element. This is just an example. The other XmlAttributes in the class are rendered as elements as well, and not as attributes like they should be. - The assemblies element is rendered as an
assemblyshould be if it were inside of theassemblieselement.
view screenshot for the above 2 items here
The XML model should look similar to this:
<?xml version="1.0" encoding="utf-8"?>
<assemblies timestamp="02/27/2018 14:32:47">
<assembly name="API.Test.dll" environment="64-bit .NET Standard [collection-per-class, parallel (8 threads)]" test-framework="xUnit.net 2.3.1.3858" run-date="2018-02-27" run-time="14:32:47" total="9" passed="5" failed="3" skipped="1" time="0.161" errors="0">
<errors />
<collection total="1" passed="0" failed="1" skipped="0" name="Test collection for API.Test.API.Results.TestResultPost2" time="0.000">
<test name="API.Test.API.Results.TestResultPost2.TestWeWontGetTo" type="API.Test.API.Results.TestResultPost2" method="TestWeWontGetTo" time="0" result="Fail">
<failure exception-type="System.Exception">
<message><![CDATA[System.Exception : exception in setup]]></message>
<stack-trace><![CDATA[ at API.Test.API.Results.TestResultPost2..ctor() in /Users//Documents///API.Test/Controller/TestResultsPost.cs:line 60]]></stack-trace>
</failure>
</test>
</collection>
...
And when I try to post XML according to the model in swagger, OR if I try to post valid XML, the results variable in the PostXunitResults method is null.
If I inspect the body of the call via Request.Body, then the first part of the XML that I posted is gone, only the last part is in the Body stream.
Any help to figure this out would be great!
<scan_details><object name="file1.xml"></object><object name="file2.json"></object></scan_details>to a method with a parameter of the ScanDetails type, and that resulted in a non-null argument. Thanks for helping me to think to simplify the model in order to step through the problem. Swagger still does not render the model correctly, but that is not as important right now.this.ModelState.IsValidin yourPostXunitResults. If it's false - inspecting that model state might give you some clues about what exactly asp.net doesn't like about what you post (and why it thinks it does not match the model).