MonoDroid:从Web服务读取大型json字符串时间歇性失败

我在一个线程上使用下面的代码(在ui中显示进度对话框)从ASP.Net MVC Web服务中读取json字符串。 数据可以在1 mb和4 mb之间。

public static class WebRequestEx { public static string ExecuteRequestReadToEnd(this WebRequest req) { var resp = req.GetResponse(); using (var resps = resp.GetResponseStream()) { StringBuilder sb = new StringBuilder(); // read through the stream loading up the string builder using (var respRdr = new StreamReader(resps)) { //return respRdr.ReadToEnd(); while (!respRdr.EndOfStream) { sb.Append(respRdr.ReadLine()); } return sb.ToString(); } } } } 

堆栈跟踪如下。

 I/mono (15666): Stacktrace: I/mono (15666): I/mono (15666): at System.Threading.WaitHandle.set_Handle (intptr)  I/mono (15666): at System.Threading.EventWaitHandle..ctor (bool,System.Threading.EventResetMode)  I/mono (15666): at System.Threading.ManualResetEvent..ctor (bool)  I/mono (15666): at (wrapper remoting-invoke-with-check) System.Threading.ManualResetEvent..ctor (bool)  I/mono (15666): at System.Net.WebAsyncResult.get_AsyncWaitHandle ()  I/mono (15666): at System.Net.WebAsyncResult.WaitUntilComplete (int,bool)  I/mono (15666): at System.Net.WebConnectionStream.Read (byte[],int,int)  I/mono (15666): at System.IO.StreamReader.ReadBuffer ()  I/mono (15666): at System.IO.StreamReader.ReadLine ()  I/mono (15666): at System.WebRequestEx.ExecuteRequestReadToEnd (System.Net.WebRequest)  

问题是每次都不会发生这种情况并且是间歇性的。 这很糟糕,因为它导致整个应用程序冻结,进度对话框因用户无法对应用程序执行任何操作而停滞不前。 我在调用代码中有一个try / catch块,但是这个exception似乎绕过它。

我之前正在使用ReadToEnd,并且间歇性地爆炸,所以我逐行切换到阅读。

堆栈跟踪不是特别有用,因为似乎在Readline()中正在进行某些操作。

思考/咨询/替代品?

除非您对WebRequest有特殊要求,否则应使用WebClient

DownloadString和(甚至更好) DownloadStringAsync可以防止您处理响应位,这样很容易分配给大量内存和临时字符串,这将影响您的应用程序性能。

尝试使用这个:

  public static string ExecuteRequestReadToEnd(this WebRequest req) { var resp = req.GetResponse(); using (var resps = resp.GetResponseStream()) { var buffer = new byte[16 * 1024]; using (var ms = new MemoryStream()) { int read; while ((read = resps.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } var content = ms.ToArray(); return Encoding.UTF8.GetString(content, 0, content.Length); } } } 

您需要增加maxArrayLength值,因为返回的byte []数组超过了16348的大小。 您可以为maxArrayLength设置的最大值也是最大Int32数,它等于2147483647.修改此设置,您的Web服务将能够在Web服务和客户端应用程序之间传输大数据。

Web.config中 ,将生成客户端的Web服务引用绑定。

“已超出传入邮件的最大邮件大小限额(65536)。要增加配额,请在相应的绑定元素上使用MaxReceivedMessageSize属性。”

将其设置为最大的32 ^ 31 – 1或2147483647最大的32位数。

注意transferMode,默认情况下是Buffered。

  • Bufferred意味着请求和响应消息都将被缓冲。

transferMode的其他枚举:

  • 式传输,这意味着请求和响应消息都将进行流式传输,或者
  • StreamingRequest ,其中请求将在响应消息缓冲时流式传输,或者
  • StreamedResponse ,在响应消息流传输时缓冲请求消息。

对于那些不知道的人,Buffered意味着传输将整个消息保存在内存缓冲区中,直到传输完成。 流式传输意味着只缓冲邮件头,而邮件正文将作为流公开。

将maxReceivedMessageSize从65536更改为2147483647 – 如果您保留transferMode =“Buffered”,我们可能会收到另一个错误:

对于TransferMode.Buffered,MaxReceivedMessageSize和MaxBufferSize必须是相同的值。 参数名称:bindingElement

如果整个消息被缓冲,则两个属性都需要相同的值,MaxReceivedMessageSize大于MaxBufferSize。

您有两种选择:a)将MaxBufferSize更改为2147483647的大小b)将transferMode设置为:Streamed,StreamedRequest或StreamedResponse。

“使用缓冲或流传输的决定是端点对HTTP传输的本地决定。对于HTTP传输,传输模式不会通过连接传播,也不会传播到代理服务器或其他中介。设置传输模式不会反映出来在服务合同的描述中,在为服务生成代理之后,您可以(允许但不需要)编辑用于流传输的服务的配置文件来设置传输模式。对于TCP和命名管道传输,传输模式作为政策断言传播。“ http://msdn.microsoft.com/en-us/library/system.servicemodel.transfermode.aspx