I try to serialize multiple items to json, and formats them as an array.
It's event based, cause it's lot of data which could not be hold in memory as a whole collection. But I need to serialize each item into a file and format it like an array.
_jsonWriter = new JsonTextWriter(new StreamWriter("Output.json")));
DataGatherer.ItemGathered += item =>
{
_jsonSerializer.Serialize(_jsonWriter, item);
_jsonWriter.Flush();
};
Currently this outputs following:
{
"Id": 218515,
"Name": "A"
}{
"Id": 118647,
"Name": "B"
}
Since the serializer serializes each item as an object an does not know its an array.
So how can I tell the JSON.Net serializer to handle each item as an item of an array and formats the data like so:
[{ "Id": 218515, "Name": "A"},{"Id": 118647,"Name": "B"}]
Thanks for any hints!
Can JSON serialize a list? Json.NET has excellent support for serializing and deserializing collections of objects. To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for.
The ToObjectCollectionSafe<TResult>() method can handle that for you. This is usable for Single Result vs Array using JSON.net and handle both a single item and an array for the same property and can convert an array to a single object.
Speed up serialization Because ArduinoJson writes bytes one by one, WiFiClient spends a lot of time sending small packets. To speed up your program, you need to insert a buffer between serializeJson() and WiFiClient . You can do that using the StreamUtils library.
I would create a simple JsonItemWriter
class to wrap the JsonTextWriter
. The class would just need to keep track of whether any items had been written to the output yet. If not, use the inner JsonTextWriter to write a StartArray to the stream before writing the item. When the outer ItemWriter is closed, write an EndArray to the stream. Then change your event handler to use the ItemWriter instead of the JsonTextWriter.
Here is what I had in mind for the JsonItemWriter
:
class JsonItemWriter
{
private JsonTextWriter innerWriter;
private JsonSerializer serializer;
public JsonItemWriter(JsonTextWriter innerWriter, JsonSerializer serializer)
{
this.innerWriter = innerWriter;
this.serializer = serializer;
}
public void WriteItem(object item)
{
if (innerWriter.WriteState == Newtonsoft.Json.WriteState.Start)
{
innerWriter.WriteStartArray();
}
serializer.Serialize(innerWriter, item);
innerWriter.Flush();
}
public void Close()
{
innerWriter.WriteEndArray();
innerWriter.Close();
}
}
Then set up your event handler like this:
_jsonWriter = new JsonTextWriter(new StreamWriter("Output.json"));
_itemWriter = new JsonItemWriter(_jsonWriter, _jsonSerializer);
DataGatherer.ItemGathered += item =>
{
_itemWriter.WriteItem(item);
};
Here's a short demo using a mock DataGatherer to stand in for yours:
class Program
{
static void Main(string[] args)
{
JsonSerializer jsonSerializer = new JsonSerializer();
JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter("Output.json"));
JsonItemWriter itemWriter = new JsonItemWriter(jsonWriter, jsonSerializer);
MockDataGatherer gatherer = new MockDataGatherer();
gatherer.ItemGathered += item =>
{
itemWriter.WriteItem(item);
};
var items = new[]
{
new { Id = 218515, Name = "A" },
new { Id = 118647, Name = "B" }
};
gatherer.SimulateReceivingItems(items);
itemWriter.Close();
using (StreamReader reader = new StreamReader("Output.json"))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
class MockDataGatherer
{
public void SimulateReceivingItems(IEnumerable<object> items)
{
foreach (object item in items)
{
ItemGathered(item);
}
}
public event ItemGatheredEventHandler ItemGathered;
public delegate void ItemGatheredEventHandler(object item);
}
Here is the output of the above (notice the objects are now wrapped in an array):
[{"Id":218515,"Name":"A"},{"Id":118647,"Name":"B"}]
Why don't you build an IEnumerable<YourObject>
.
It does not need to loead all the collection in your memory and when you give it to the serialiazer, it is parsed as an array.
A simple way to do that would be to replace your ItemGathered
event call by a simple
yield return
As you
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With