Azure上的大JSON流
我正在开发一个大数据导出API,但当它需要将大数据作为JSON传输时,我遇到了一些问题。这方面的一个例子是超过400万条记录的转移。当保存为文本文件时,数据被设置为大约380MB,但是由于某些原因,流被切断到大约250~280MB(总是不同的),并且当我在记事本中检查文件时,它只切断了记录中间的数据。 这种行为只发生在Azure服务器上,我可以通过本地IIS下载完整文件。同样奇怪的是,当我将数据导出为XML时,导致+600MB的更大文件没有这个问题 我们的Azure应用程序服务计划是S3(4核,7GB内存),我认为这应该足够了,实际传输数据的代码是以下函数:Azure上的大JSON流,azure,asp.net-core-2.0,Azure,Asp.net Core 2.0,我正在开发一个大数据导出API,但当它需要将大数据作为JSON传输时,我遇到了一些问题。这方面的一个例子是超过400万条记录的转移。当保存为文本文件时,数据被设置为大约380MB,但是由于某些原因,流被切断到大约250~280MB(总是不同的),并且当我在记事本中检查文件时,它只切断了记录中间的数据。 这种行为只发生在Azure服务器上,我可以通过本地IIS下载完整文件。同样奇怪的是,当我将数据导出为XML时,导致+600MB的更大文件没有这个问题 我们的Azure应用程序服务计划是S3(4核,
public IActionResult ResponseConvert(IList data)
{
return new Microsoft.AspNetCore.Mvc.JsonResult(data);
}
数据参数是一个列表
对象,包含+400万条记录
乍一看,Azure似乎提前终止了流,知道为什么以及如何防止吗?最后,我编写了自己的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();
}
}
}
}
}
使用Microsoft.AspNetCore.Mvc;
使用Newtonsoft.Json;
使用系统集合;
使用System.Collections.Generic;
运用系统动力学;
使用System.IO;
使用System.Linq;
使用系统文本;
命名空间MyProject.OutputFormat
{
公共类JsonResult:ActionResult
{
私有只读IList_数据;
公共格式{get;set;}
公共字符串MimeType{get;set;}
公共JsonResult(IList数据)
{
_数据=数据;
//默认值
MimeType=“应用程序/json”;
格式化=格式化。无;
}
public override void executesult(ActionContext上下文)
{
context.HttpContext.Response.ContentType=MimeType;
使用(var sw=newstreamwriter(context.HttpContext.Response.Body,Encoding.UTF8))
{
使用(var writer=newjsontextwriter(sw){Formatting=Formatting})
{
writer.writestarray();
如果(_data!=null)
{
foreach(变量项在_数据中)
{
writer.WriteStartObject();
如果(项目为ExpandooObject)
{
foreach(项中的KeyValuePair属性作为ExpandooObject)
{
writer.WritePropertyName(prop.Key);
writer.WriteValue(prop.Value!=null?prop.Value.GetType().Name!=“Byte[]”?prop.Value.ToString():((Byte[])prop.Value.BinaryToString():null);
}
}
其他的
{
var props=item.GetType().GetProperties()。其中(i=>i.Name!=“item”);
foreach(道具中的var道具)
{
var val=道具获取值(项目);
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字符串
值得注意的是,尽管这适用于更大的数据,但JsonResult会加快Microsoft.AspNetCore.Mvc的下载速度。获得对客户端的响应同样快,但由于此方法仅在下载期间转换,因此需要更长的时间才能完全下载流。如果您的环境中没有任何问题,我建议您使用Microsoft.AspNetCore.Mvc中的问题。类似于?可能问题的原因类似,但建议的答案并不相关。在这种情况下,发布的唯一真实答案(ReferenceLoopHandling)没有影响,因为动态对象只有简单的类型属性,并且没有对其他类的引用。我建议使用
Convert.ToBase64String
,而不是BinaryToString
。。。不需要重新发明轮子。。。