We need the BSON equivalent to
{
"Header": {
"SubHeader1": {
"Name": "Bond",
"License": 7
},
"SubHeader2": {
"IsActive": true
}
},
"Payload": /* This will be a 40GB byte stream! */
}
But what we get is:

As you can see, the payload comes FIRST, and then the rest of the header!
We're using Json.NET's BSON writer (Bson.BsonWriter.WriteValue(byte[] value)), but it only accepts an actual byte[], not Stream. Since our payloads will be 10s of GB, we must use streams, so we've tried to work around (code below) but that gives us the incorrect result shown above
public void Expt()
{
// Just some structure classes, defined below
var fileStruct = new FileStructure();
using (Stream outputSt = new FileStream("TestBinary.bson", FileMode.Create))
{
var serializer = new JsonSerializer();
var bw = new BsonWriter(outputSt);
// Start
bw.WriteStartObject();
// Write header
bw.WritePropertyName("Header");
serializer.Serialize(bw, fileStruct.Header);
// Write payload
bw.WritePropertyName("Payload");
bw.Flush(); // <== flush !
// In reality we 40GB into the stream, dummy example for now
byte[] dummyPayload = Encoding.UTF8.GetBytes("This will be a 40GB byte stream!");
outputSt.Write(dummyPayload, 0, dummyPayload.Length);
// End
bw.WriteEndObject();
}
}
This looks like the classic case of no synchronization / not flushing buffers despite us actually issuing a Flush to Json.NET before writing the payload to the underlying stream.
Question: Is there another way to do this? We'd rather not fork off Json.NET's source (and exploring it's internal piping) or re-invent the wheel somehow ...
Details: The supporting structure classes are (if you want to repro this)
public class FileStructure
{
public TopHeader Header { get; set; }
public byte[] Payload { get; set; }
public FileStructure()
{
Header = new TopHeader
{
SubHeader1 = new SubHeader1 {Name = "Bond", License = 007},
SubHeader2 = new SubHeader2 {IsActive = true}
};
}
}
public class TopHeader
{
public SubHeader1 SubHeader1 { get; set; }
public SubHeader2 SubHeader2 { get; set; }
}
public class SubHeader1
{
public string Name { get; set; }
public int License { get; set; }
}
public class SubHeader2
{
public bool IsActive { get; set; }
}
BsonWriterwrites data only at the end of objects (seeBsonWriter.WriteEnd). Looks like you'll have to copy into your project and modify quite a bit of classes (BsonWriter,BsonBinaryWriter, the wholeBsonTokenhierarchy etc.) in order to implement writing streams, as they are not designed to be extensible. The feature looks quite useful, so I suggest modifying the code of the library and making a pull request. There will be some limitations, by the way; one requirement is that the stream needs to support telling its length.