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

时间:2011-11-17 13:17:44

标签: c# android multithreading mono xamarin.android

我在线程上使用下面的代码(在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) <0x0008b>
I/mono    (15666):   at System.Threading.EventWaitHandle..ctor (bool,System.Threading.EventResetMode) <0x00053>
I/mono    (15666):   at System.Threading.ManualResetEvent..ctor (bool) <0x0001f>
I/mono    (15666):   at (wrapper remoting-invoke-with-check) System.Threading.ManualResetEvent..ctor (bool) <0xffffffff>
I/mono    (15666):   at System.Net.WebAsyncResult.get_AsyncWaitHandle () <0x00073>
I/mono    (15666):   at System.Net.WebAsyncResult.WaitUntilComplete (int,bool) <0x00033>
I/mono    (15666):   at System.Net.WebConnectionStream.Read (byte[],int,int) <0x000b3>
I/mono    (15666):   at System.IO.StreamReader.ReadBuffer () <0x00047>
I/mono    (15666):   at System.IO.StreamReader.ReadLine () <0x0014b>
I/mono    (15666):   at System.WebRequestEx.ExecuteRequestReadToEnd (System.Net.WebRequest) <0x000ab>

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

我之前使用的是ReadToEnd,并且间歇性地爆发了,所以我逐渐切换到了阅读。

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

思想/忠告/替代?

3 个答案:

答案 0 :(得分:0)

尝试使用这个:

    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);
            }
        }
    }

答案 1 :(得分:0)

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

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

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

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

注意transferMode,默认情况下是缓冲。

  • Bufferred 表示请求和响应消息都将被缓冲。

transferMode的其他枚举:

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

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

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

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

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

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

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

答案 2 :(得分:0)

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

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

相关问题