Open bergner opened 5 years ago
@imcarolwang We need to compare the raw soap body content of the PUT and POST calls and see what the difference is. Please use the example provided to create a repro in order to get this info.
We are building a CoreWCF service and faced this issue when we enabled request buffering.
Steps:
HttpContext.Request.EnableBuffering();
HttpContext.Request.InputStream
, it returns stream of type FileBufferingReadStream
XmlReader xmlReader = XmlReader.Create(stream)
.XmlReader.Read()
throws exception "Root element is missing"
At https://github.com/bergner/netcore-bugs/ I've provided a webapi example that reproduces this problem. It uses netcoreapp2.1.
This starts a service with POST and PUT support on /api/Values/. The POST endpoint uses [FromBody] SyndicationItem and the PUT endpoint uses [FromBody] XmlElement. In Startup.cs context.Request.EnableBuffering() is called (before app.UseMvc()). The request buffering is a key component to the issue here.
This causes ASP.NET Core to switch the context.Request.Body from a Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream object to a Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream object.
The service has a AtomEntryInputFormatter class which is used to parse the incoming HTTP request into a SyndicationItem object (using XmlReader, see below). It is also using an XmlSerializerInputFormatter to support the PUT requests (which are used for comparison here).
A sample input xml below:
Using PUT to the XmlElement endpoint works ok. I get a 200 response and the controller gets the expected data (which can be seen in Console.WriteLine output from the server).
The POST request fails with a 400 Bad request:
And the log shows an exception:
Workaround
I have found 2 workarounds for this problem:
XmlReader reader = XmlReader.Create(context.HttpContext.Request.Body)
directly in preparation forSyndicationItem.Load(reader)
. Instead wrap the body stream withnew StreamReader(context.HttpContext.Request.Body)
then use that with XmlReader.Create.Removing EnableBuffering() also makes the problem go away but there are many circumstances where you want/need to have request buffering enabled so it is not a viable workaround.
Expected result
The reading / parsing from context.HttpContext.Request.Body should have the same behavior regardless if EnableBuffering is used or not, and when buffering is used it should not matter it the body has been read prior to reaching SyndicationItem.Load.