I'm studying C# and trying to get the code below to parse an incoming JSON recipe string that I convert to an XML document and I'm getting the following error
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ConsumeStringAndValidate(ReadOnlySpan`1 data, Int32 idx)
at System.Text.Json.Utf8JsonReader.ConsumeString()
at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.JsonDocument.Parse(ReadOnlySpan`1 utf8JsonSpan, Utf8JsonReader reader, MetadataDb& database, StackRowStack& stack)
at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 utf8Json, JsonReaderOptions readerOptions, Byte[] extraRentedBytes)
at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 json, JsonDocumentOptions options)
at System.Text.Json.JsonDocument.Parse(String json, JsonDocumentOptions options)
I'm unsure as to why it's not working as the data I send to parse is a string. It works for simple strings however when sending a 'recipe' it throws the exception. The recipe is just a string that I create an XML document from (learning exercise). The recipe code is valid but it seems the JSON reader has issues parsing this string, I could be wrong in this. Here's the code:
TCP receive data method
private async Task Listen()
{
try
{
while (true)
{
Token.ThrowIfCancellationRequested();
TcpClient client = await server.AcceptTcpClientAsync();
Console.WriteLine("Connected!");
await Task.Run(async () => await HandleDevice(client), Token);
}
}
catch (SocketException e)
{
Console.WriteLine("Exception: {0}", e);
}
}
private async Task HandleDevice(TcpClient client)
{
string imei = String.Empty;
string data = null;
Byte[] bytes = new Byte[80196];
int i;
try
{
using (stream = client.GetStream())
{
while ((i = await stream.ReadAsync(bytes, 0, bytes.Length, Token)) != 0)
{
Token.ThrowIfCancellationRequested();
string hex = BitConverter.ToString(bytes);
data = Encoding.UTF8.GetString(bytes, 0, i);
Console.WriteLine(data);
processData(data);
}
}
}
catch (OperationCanceledException) { }
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e.ToString());
}
finally
{
client.Close();
}
}
Process data method
public static void processData(string data)
{
var jsonOptions = new JsonDocumentOptions
{
AllowTrailingCommas = true,
};
using (JsonDocument document = JsonDocument.Parse(data, jsonOptions))
{
JsonElement root = document.RootElement;
// FOR DEBUGGING
// foreach (JsonProperty element in root.EnumerateObject())
//{
// Console.WriteLine($"{element.Name} ValueKind={element.Value.ValueKind} Value={element.Value}");
//}
// Parse the data response
if (root.TryGetProperty("data", out JsonElement contentToParse))
{
if (string.IsNullOrEmpty(contentToParse.GetString()) == false)
{
// Data to parse
if (contentToParse.GetString().Contains("RECIPE:"))
{
string[] recipe = contentToParse.GetString().Split(':');
sendToFront(recipe[1]);
}
else
{
Console.WriteLine("Something else to parse {0}", contentToParse.GetString());
}
}
}
}
}
My incoming JSON String looks like this: {"user": "me", "data": "RECIPE:<?xml version='1.0'..."} - The response is valid JSON and tested by online validators.
UPDATE: I've inspected the issue via console and it appears that only part of the recipe is received which could be causing the issue. How can I get the full JSON string before sending it to the processData method?
ReadAsyncdoesn't necessarily read a full JSON object, it might be more or less than one whole object. You need some kind of framing so that you know where one ends and the next begins. A common solution is to read a 4-bytesizevalue from the stream, then read that many bytes. AStreamReadercan do this quite neatly