Azure上的大型JSON流

时间:2018-07-02 10:48:32

标签: azure asp.net-core-2.0

我正在开发大数据导出API,但是当它需要将大数据作为JSON传输时,我遇到了一些问题。这样的例子是超过400万条记录的转移。当保存为文本文件时,数据原本大约为380MB,但是由于某种原因,流被缩短到大约250-280MB(总是不同),当我在记事本中检查文件时,它确实切断了其中的数据。记录的中间。

此行为仅在Azure服务器上发生,我可以通过本地IIS下载完整文件。同样奇怪的是,当我将数据导出为XML时,导致更大的文件+ 600MB并没有这个问题。

我们的Azure应用服务计划是S3(4核,7GB内存),我认为这已经足够了,实际传输数据的代码是以下功能:

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

data参数是List<dynamic>对象,包含+4百万条记录。

乍一看,Azure似乎会提前终止流,是否知道为什么以及如何防止这种情况发生?

1 个答案:

答案 0 :(得分:2)

最后,我编写了自己的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()方法是对byte []的自写扩展,用于将字节数组转换为base64字符串。

请注意,尽管这适用于更大的数据,但是Microsoft.AspNetCore.Mvc中的JsonResult下载速度更快。获得对客户端的响应速度一样快,但是由于此方法仅在下载期间进行转换,因此需要花费更长的时间才能完全下载流。如果您的环境中没有任何问题,建议您使用Microsoft.AspNetCore.Mvc中的问题。