Search code examples
c#encodingmonoxamarin.androidasciiencoding

MonoDroid : Encoding.ASCII.GetString failing


Intermittently, Encoding.ASCII.GetString call fails with an exception that escapes all the catch blocks in place and freezes the app.

private string ExecuteRequest(Uri url, KeyValuePair<string, string>[] postItems = null)
{
    var data = new byte[0];
    var response = new byte[0];
    using (var client = new WebClient())
    {
        if (postItems != null && postItems.Count() > 0)
        {
            string dataString = string.Join("&", postItems.Select(
                                    item => string.Format("{0}={1}", item.Key, item.Value)).ToArray());
            data = new ASCIIEncoding().GetBytes(dataString);
        }
        response = client.UploadData(url, "POST", data);
        Android.Util.Log.Info("info", "response from the post received. about to get string");
        client.Dispose();
    }
    try
    {
        return Encoding.ASCII.GetString(response);
    }
    catch (Exception ex)
    {
        Android.Util.Log.Info("info", 
            "Encoding.ASCII.GetString Exception : {0}, {1}", ex.Message, ex.StackTrace);
        throw new ApplicationException("UnRecoverable. Abort");
    }            
}

StackTrace I get is

I/sssvida (10960): response from the post received. about to get string
I/mono    (10960): Stacktrace:
I/mono    (10960):
I/mono    (10960):   at System.Text.ASCIIEncoding.GetString (byte[],int,int) <0x000cb>
I/mono    (10960):   at System.Text.Encoding.GetString (byte[]) <0x00037>
I/mono    (10960):   at ServiceRequest.ExecuteRequest (System.Uri,System.Collections.Generic.KeyValuePair`2<string, string>[]) <0x0026b>

Intermitently, I am getting an unusal stacktrace shown below

I/mono    ( 9817): Stacktrace:
I/mono    ( 9817):
F/        ( 9817): * Assertion at ../../../../mono/mini/mini-exceptions.c:472, condition `class' not met
D/dalvikvm(  220): GC_EXPLICIT freed 1K, 35% free 17547K/26759K, paused 3ms+3ms

The response is json data that can range between 1 - 4 mb.

Please help. Thanks!!!!

Edit 2 : I updated the code to use UploadString instead of UploadData and intermittently I get this :

I/mono    (15065): Stacktrace:
I/mono    (15065):
I/mono    (15065):   at string.CreateString (char[]) <0x0004b>
I/mono    (15065):   at (wrapper managed-to-managed) string..ctor (char[]) <0xffffffff>
I/mono    (15065):   at System.Text.Encoding.GetString (byte[],int,int) <0x00043>
I/mono    (15065):   at System.Text.UTF8Encoding.GetString (byte[],int,int) <0x0002b>
I/mono    (15065):   at System.Text.Encoding.GetString (byte[]) <0x00037>
I/mono    (15065):   at System.Net.WebClient.UploadString (System.Uri,string,string) <0x0007f>
I/mono    (15065):   at (wrapper remoting-invoke-with-check) System.Net.WebClient.UploadString (System.Uri,string,string) <0xffffffff>

Solution

  • Paging data and downloading in chunks might be the only correct and scalable/robust solution here.

    For now, the code below is not blowing up, it may be that I have not hit the tipping point. But this is my first pass at chunking on the device. Encoding.ASCII.GetString does not blowing up in the code below.

    private string ExecuteRequest(Uri url, KeyValuePair<string, string>[] postItems = null)
    {
        var data = new byte[0];
        var response = new byte[0];
        ///switched to WebClient because
        /// http://stackoverflow.com/questions/8167726/monodroid-intermittent-failure-when-reading-a-large-json-string-from-web-servi
        using (var client = new WebClient())
        {
            if (postItems != null && postItems.Count() > 0)
            {
                string dataString = string.Join("&", postItems.Select(
                                        item => string.Format("{0}={1}", item.Key, item.Value)).ToArray());
                data = new ASCIIEncoding().GetBytes(dataString);
            }
            response = client.UploadData(url, "POST", data);
            Android.Util.Log.Info("info", "response from the post received. about to get string");
            client.Dispose();
        }
        try
        {
            Android.Util.Log.Info("info", "response size : {0}", response.Length);
            var chunkSize = 50000;
            if (response.Length > chunkSize)
            {
                var returnValue = new StringBuilder();
                for (int i = 0; i < response.Length; i+= chunkSize)
                {                        
                    int end = (i + chunkSize) > response.Length ? response.Length - i : chunkSize;
                    returnValue.Append(Encoding.ASCII.GetString(response, i, end));
                    Android.Util.Log.Info("info", "added a chunk from {0} to {1}", i, end);
                }
                return returnValue.ToString();
            }
            return Encoding.ASCII.GetString(response);
        }
        catch (Exception ex)
        {
            Android.Util.Log.Info("info", 
                "Encoding.ASCII.GetString Exception : {0}, {1}", ex.Message, ex.StackTrace);
            throw new ApplicationException("UnRecoverable. Abort");
        }            
    }