I am really surprised by this issue because I remember succeeding in it in an earlier .NET Core version. I am working on a .NET Core 2.2 application which now needs to be called by another application (developed externally) which can only post xml....
This is my ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddXmlSerializerFormatters();
}
This is my controller:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// POST api/values
[HttpPost]
public ActionResult<object> Post([FromBody] object value)
{
return ("Hi", "Hi2");
}
}
The following requests do cause a response with status code 200:
POST http://localhost:58774/api/values
Content-Type: application/json
Accept: application/xml
User-Agent: vscode-restclient
Accept-Encoding: gzip
{"a":5}
which gives me xml as a response and
POST http://localhost:58774/api/values
Content-Type: application/json
Accept: application/json
User-Agent: vscode-restclient
Accept-Encoding: gzip
{"a":5}
which gives json as a response.
However, this call results in a response with status code 500 (which is exactly my problem):
POST http://localhost:58774/api/values
Content-Type: application/xml
Accept: application/xml
User-Agent: vscode-restclient
Accept-Encoding: gzip
<A a="5"/>
So now I am in trouble. Xml formatting works which becomes clear if I Accept it as an output type. However, if I post it myself as a Content-Type and test that, I get a 500. I also tried this (old) approach but it does not seem to work in .NET Core 2.2 . What am I doing wrong? How can I post my xml in .net core 2.2?
An update after a useful remark. The exception causing the 500 is this one:
System.InvalidOperationException: There is an error in XML document (1, 11). ---> System.InvalidOperationException: was not expected.
However, if I add an xmlns (based on this), I still have the 500:
POST http://localhost:5000/api/values
Content-Type: application/xml
Accept: application/xml
User-Agent: vscode-restclient
Accept-Encoding: gzip
<f:table xmlns:f="https://www.w3schools.com/furniture">
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
Then the exception message is:
System.InvalidOperationException: There is an error in XML document (1, 56). ---> System.InvalidOperationException: https://www.w3schools.com/furniture'> was not expected.
Probably, I need to change my xml. How? Even the example from w3cschools does not help me.
For Content-Type: application/json
with {"a":5}
, you will receive { "a": 5 }
at server side. It received plain text.
For Content-Type: application/xml
with <A a="5"/>
, if you prefer receive <A a="5" />
, you could implement custom XDocumentInputFormatter
like
public class XDocumentInputFormatter : InputFormatter, IInputFormatter, IApiRequestFormatMetadataProvider
{
public XDocumentInputFormatter()
{
SupportedMediaTypes.Add("application/xml");
}
protected override bool CanReadType(Type type)
{
if (type.IsAssignableFrom(typeof(XDocument))) return true;
return base.CanReadType(type);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var xmlDoc = await XDocument.LoadAsync(context.HttpContext.Request.Body, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
}
Register it in Startup.cs
services.AddMvc(config =>
{
config.InputFormatters.Insert(0, new XDocumentInputFormatter());
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddXmlSerializerFormatters();
By default, For XmlSerializer
, we need to provide Type type
, an object type would not be able to deserialize.
If the type of object value
is definted like
public class A
{
public int a { get; set; }
}
You could change your method like
public ActionResult<object> Post([FromBody] A value)
{
return new A { a = 1 };//("Hi", "Hi2");
}
And with request like
<A>
<a>1</a>
</A>
It will fill value with class A object.