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