У меня есть ответ OData в виде JSON (, что составляет несколько МБ ) , и требуется потоковая передача "определенных частей JSON", даже не загружая их в память.
Например : когда я читаю свойство "value[0].Body.Content
" в следующем JSON (которое будет в МБ), я хочу передать эту часть значениябез десериализации его в объект типа строка.Поэтому в основном считайте часть значения в байтовый массив фиксированного размера и запишите этот байтовый массив в целевой поток (повторяя шаг до тех пор, пока эти данные не закончат обработку).
JSON:
{
"@odata.context": "https://localhost:5555/api/v2.0/$metadata#Me/Messages",
"value": [
{
"@odata.id": "https://localhost:5555/api/v2.0/",
"@odata.etag": "W/\"Something\"",
"Id": "vccvJHDSFds43hwy98fh",
"CreatedDateTime": "2018-12-01T01:47:53Z",
"LastModifiedDateTime": "2018-12-01T01:47:53Z",
"ChangeKey": "SDgf43tsdf",
"WebLink": "https://localhost:5555/?ItemID=dfsgsdfg9876ijhrf",
"Body": {
"ContentType": "HTML",
"Content": "<html>\r\n<body>Huge Data Here\r\n</body>\r\n</html>\r\n"
},
"ToRecipients": [{
"EmailAddress": {
"Name": "ME",
"Address": "me@me.com"
}
}
],
"CcRecipients": [],
"BccRecipients": [],
"ReplyTo": [],
"Flag": {
"FlagStatus": "NotFlagged"
}
}
],
"@odata.nextLink": "http://localhost:5555/rest/jersey/sleep?%24filter=LastDeliveredDateTime+ge+2018-12-01+and+LastDeliveredDateTime+lt+2018-12-02&%24top=50&%24skip=50"
}
Подходы пробовали: 1. Newtonsoft
Сначала я попытался использовать потоковую передачу Newtonsoft, но она внутренне преобразует данные в строку и загружает в память .(Это приводит к тому, что LOH начинает работать, а память не освобождается до тех пор, пока не произойдет сжатие - у нас есть ограничение памяти для нашего рабочего процесса, и мы не можем сохранить его в памяти)
**code:**
using (var jsonTextReader = new JsonTextReader(sr))
{
var pool = new CustomArrayPool();
// Checking if pooling will help with memory
jsonTextReader.ArrayPool = pool;
while (jsonTextReader.Read())
{
if (jsonTextReader.TokenType == JsonToken.PropertyName
&& ((string)jsonTextReader.Value).Equals("value"))
{
jsonTextReader.Read();
if (jsonTextReader.TokenType == JsonToken.StartArray)
{
while (jsonTextReader.Read())
{
if (jsonTextReader.TokenType == JsonToken.StartObject)
{
var Current = JToken.Load(jsonTextReader);
// By Now, the LOH Shoots up.
// Avoid below code of converting this JToken back to byte array.
destinationStream.write(Encoding.ASCII.GetBytes(Current.ToString()));
}
else if (jsonTextReader.TokenType == JsonToken.EndArray)
{
break;
}
}
}
}
if (jsonTextReader.TokenType == JsonToken.StartObject)
{
var Current = JToken.Load(jsonTextReader);
// Do some processing with Current
destinationStream.write(Encoding.ASCII.GetBytes(Current.ToString()));
}
}
}
OData.Net:
Я думал, можно ли это сделать с помощью библиотеки OData.Net, поскольку она выглядит так, как будто она поддерживает потоковую передачу строковых полей ,Но я не мог уйти далеко, так как в итоге я создал Модель для данных, что означало бы, что значение будет преобразовано в один строковый объект из МБ.
Код
ODataMessageReaderSettings settings = new ODataMessageReaderSettings();
IODataResponseMessage responseMessage = new InMemoryMessage { Stream = stream };
responseMessage.SetHeader("Content-Type", "application/json;odata.metadata=minimal;");
// ODataMessageReader reader = new ODataMessageReader((IODataResponseMessage)message, settings, GetEdmModel());
ODataMessageReader reader = new ODataMessageReader(responseMessage, settings, new EdmModel());
var oDataResourceReader = reader.CreateODataResourceReader();
var property = reader.ReadProperty();
Есть идеи, как разбирать этот JSON по частям, используя OData.Net/Newtonsoft и потоковое значение определенных полей?Это единственный способ сделать это, вручную проанализировать поток?