I'm facing a strange bug, where .NET Core 2.1 API seems to ignore a JSON body on certain cases.
- I advised many other questions (e.g
To be sure, the
Content-Typeheader is set toapplication/json. Also, FWIW, theHttpWebRequestbody is set as follows:using(var requestStream = httpWebRequest.GetRequestStream()) { JsonSerializer.Serialize(payload, requestStream); }And called with:
var response = (HttpWebResponse)request.GetResponse();Question
Why does
bodyis null when used withHttpWebRequest? Why does the JSON converter read methods are skipped in such cases?CodePudding user response:
The problem was in the underlying code of the serialization. So this line:
JsonSerializer.Serialize(payload, requestStream);Was implemented using the default
UTF8property:public void Serialize<T>(T instance, Stream stream) { using(var streamWriter = new StreamWriter(stream, Encoding.UTF8) // <-- Adds a BOM using(var jsonWriter = new JsonTextWriter(streamWriter)) { jsonSerializer.Serialize(jsonWriter, instance); // Newtonsoft.Json's JsonSerializer } }The default
UTF8property adds a BOM character, as noted in the documentation:It returns a UTF8Encoding object that provides a Unicode byte order mark (BOM). To instantiate a UTF8 encoding that doesn't provide a BOM, call any overload of the UTF8Encoding constructor.
It turns out that passing the BOM in a json is not allowed per the spec:
Implementations MUST NOT add a byte order mark (U FEFF) to the beginning of a networked-transmitted JSON text.
Hence .NET Core
[FromBody]internal deserialization failed.Lastly, as for why the following did work (see demo here):
using (var reader = new StreamReader(context.Request.Body)) { var requestBody = await reader.ReadToEndAsync(); // works var parsed = JObject.Parse(requestBody); }I'm not very sure. Certainly,
StreamReaderalso usesUTF8property by default (see remarks here), so it shouldn't remove the BOM, and indeed it doesn't. Per a test I did (see it here), it seems thatReadToEndis responsible for removing the BOM.For elaboration:
