2012-01-27 78 views
3

我有一个查询数据库并返回JSON的WCF4 REST服务。尽管我很难返回字符串,但有些用户希望做出非常大的查询。例如,我需要返回一个500M JSON字符串(所有数据都是ASCII文本),但是当我尝试从.NET的本机UTF-16转换字符串时,我遇到了OutOfMemoryException。这是我正在做的一个简洁的样本。将大字符串转换为UTF-8

[WebInvoke(UriTemplate="/RunQuery", ResponseFormat=WebMessageFormat.Json)] 
public Stream RunQuery() { 
    // Perform query and return serialized json string (~500 million ASCII characters) 
    string json = DoQuery(HttpContext.Current.Request.Form); 
    // Set output charset 
    WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8"; 
    // Convert UTF-16 string to UTF-8 (OutOfMemoryException) 
    byte jsonBytes[] = System.Text.Encoding.UTF8.GetBytes(json) 
    // Send UTF-8 string, without BOM 
    return new MemoryStream(jsonBytes); 
} 

如果我把JSON低于200M左右,它才有效。当它运行时,我看到IIS进程的内存使用量逐渐增加,然后爆炸到2.8G,并在此时死亡。堆栈跟踪报告它发生在System.String.ToCharArray。我尝试了将字符串分块来构建字节数组的变体,但似乎没有任何工作。任何想法如何我可以发送这些数据而不用炸毁?

+2

500M JSON?哎哟。难道你不能将数据分成页面吗? – 2012-01-27 20:33:40

+0

只是一个猜测:你可以尝试写入响应数据到一个临时文件块,然后返回一个打开的流为临时文件? (最好你应该重新构造DoQuery(),以便它支持将其结果写入输出流而不是返回流。如果不需要,你实际上不应该缓存整个兆字节的数据。) – millimoose 2012-01-27 20:34:53

+0

或将数据流传回客户端.... – Polity 2012-01-27 20:35:39

回答

0

您可以通过编写自己的stream实现来解决此问题,该实现将输入转换为实时转换为utf8。

您应该可以通过提取输入字符串的一部分,并将它们逐块转换为utf 8来实现。

请记住,字节数并非与字符数相同,除非您永远不会发送任何类型的国际字符。

0

如果您必须返回流 - 使用文件流或至少预先分配MemoryStream空间。

如果你坚持使用500MB的字符串:

  • 使用64位机和64位进程。 x86进程不太可能成功分配2个这样大小的内存。请注意,即使您使用64位进程,CLR也会限制大约2Gb的“单块分配”大小,从而使1Gb字符串不太可能适合内存。因此,在接近500Mb的某个点 - 1Gb切换到64位将不再有帮助。

  • 使用作家 - 他们可以轻松地(即http://msdn.microsoft.com/en-us/library/3aadshsx.aspx)直接编码到输出,同时编写JSON它。作为附加建议 - 甚至不要创建JSON字符串,而是将输出写入Writer。

  • 如果你知道你的字符串只有ASCII码 - 通过写入流来欺骗你自己将每个字符转换为字节。

+0

不幸的是,我的服务必须是32位才能使用Oracle odp.net驱动程序(Oracle.DataAccess.dll)这似乎没有64位的味道。 当我做一个“新的MemoryStream(500000000)”它死了,可能是因为我有一个500000000字符串坐在内存中。这确实绕过了整个字节数组,这有所帮助。 JSON由JavaScriptSerializer生成,它使我可以选择String或StringBuilder作为输出。我希望我可以简单地返回我的序列化对象,但它使用嵌套字典... – Vimm 2012-01-27 23:23:51

+0

我看到 - 你必须非常小心,在32位过程中获得大量结果,即2个这样的请求同时将会终止你的服务器。考虑使用json.net序列化程序(json.codeplex.com),因为它为您提供了比内置的更高的灵活性 - http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonTextWriter.htm。否则,我看到的唯一选择是编写自己的JSON序列化并直接写入响应流... – 2012-01-27 23:55:50