Большой поток JSON на Azure - PullRequest
0 голосов
/ 02 июля 2018

Я работаю над API экспорта больших данных, но у меня возникают проблемы, когда ему нужно передавать большие данные как JSON. Примером этого является передача более 4 миллионов записей. При сохранении в виде текстового файла размер данных составляет около 380 МБ, но по какой-то причине поток прерывается до 250–280 МБ (всегда разный), и когда я проверяю файл в блокноте, он просто обрезает данные в середина записи.

Это происходит только на сервере Azure, я могу загрузить полный файл через локальный IIS. Также странно то, что при экспорте данных в формате XML, в результате чего файл размером более 600 МБ не имел этой проблемы.

Наш план обслуживания приложений Azure - S3 (4 ядра, 7 ГБ памяти), которого, как мне кажется, должно быть достаточно; код, который фактически передает данные, представляет собой следующую функцию:

public IActionResult ResponseConvert(IList data)
{
    return new Microsoft.AspNetCore.Mvc.JsonResult(data);
}

Параметр данных - это объект List<dynamic>, содержащий записи +4 млн.

На первый взгляд кажется, что Azure прерывает поток преждевременно, есть идеи, почему и как это можно предотвратить?

1 Ответ

0 голосов
/ 18 июля 2018

В конце я написал свой собственный класс JsonResult, который будет использовать JsonTextWriter для передачи данных. Похоже, что это нормально работает с большими объектами, даже в Azure.

Вот полный класс:

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;

namespace MyProject.OutputFormat
{
    public class JsonResult : ActionResult
    {
        private readonly IList _data;

        public Formatting Formatting { get; set; }
        public string MimeType { get; set; }

        public JsonResult(IList data)
        {
            _data = data;


            // Default values
            MimeType = "application/json";
            Formatting = Formatting.None;
        }

        public override void ExecuteResult(ActionContext context)
        {
            context.HttpContext.Response.ContentType = MimeType;
            using (var sw = new StreamWriter(context.HttpContext.Response.Body, Encoding.UTF8))
            {
                using (var writer = new JsonTextWriter(sw) { Formatting = Formatting })
                {
                    writer.WriteStartArray();
                    if (_data != null)
                    {
                        foreach (var item in _data)
                        {
                            writer.WriteStartObject();
                            if (item is ExpandoObject)
                            {
                                foreach (KeyValuePair<string, object> prop in item as ExpandoObject)
                                {
                                    writer.WritePropertyName(prop.Key);
                                    writer.WriteValue(prop.Value != null ? prop.Value.GetType().Name != "Byte[]" ? prop.Value.ToString() : ((byte[])prop.Value).BinaryToString() : null);
                                }
                            }
                            else
                            {
                                var props = item.GetType().GetProperties().Where(i => i.Name != "Item");
                                foreach (var prop in props)
                                {
                                    var val = prop.GetValue(item);
                                    writer.WritePropertyName(prop.Name);
                                    writer.WriteValue(val != null ? val.GetType().Name != "Byte[]" ? val.ToString() : ((byte[])val).BinaryToString() : null);
                                }
                            }
                            writer.WriteEndObject();
                        }
                    }
                    writer.WriteEndArray();
                }
            }
        }
    }
}

Метод BinaryToString (), который вы видите, представляет собой собственное расширение байта [] для преобразования байтового массива в строку base64.

Небольшое примечание, хотя это работает для больших данных, JsonResult в Microsoft.AspNetCore.Mvc загружается быстрее. Получение ответа клиенту происходит так же быстро, но поскольку этот метод преобразуется только во время загрузки, потребуется немного больше времени, пока поток не будет полностью загружен. Если у вас нет проблем в вашей среде, я бы посоветовал использовать одну из них в Microsoft.AspNetCore.Mvc.

...