Search code examples
c#arrayswcfxamarin

Xamarin android app crashes when picture to transfer to wcf is greater than 10kb


I am developing an android mobile app using vs2017 C# which communicates with a wcf service through a web reference. One of the things it does is transfer data to an sql database that consists of strings as strings and a picture from gallery as a byte array. The transfer works well when the size of the picture is approximately below 10kb and it crashes when the size of the picture is bigger than 10kb (approximately).

The code on the mobile app (minimized for simplicity) is as follows

   private void BtnPostForFree_Click(object sender, EventArgs e)
    {
        string title = txtTitleInput.Text.Trim();
        string category = spnCategory.SelectedItem.ToString();
        string subcategory = spnSubCategory.SelectedItem.ToString();
        string prdProdCategory = spnProdProdCat.SelectedItem.ToString();
        string price = txtPriceIn.Text.Trim();
        string description = txtDesc.Text.Trim();
        TheSuk.SukMain sukAccess = new TheSuk.SukMain();// TheSuk.SukMain is a web service reference
        sukAccess.Post4FreeCompleted += SukAccess_Post4FreeCompleted; //Please see the firedup event below if neccessary
        sukAccess.Post4FreeAsync(title, category, subcategory, prdProdCategory, price, description, prodPic);
//prodPic was captured earlier with "Add Photo" button
    }

The following code adds the pic needed for the variable mentioned prodPic which is accessible to all functions

   private void BtnPicAdd_Click(object sender, EventArgs e)
    {
        Intent galleryIntent = new Intent();
        galleryIntent.SetType("image/*");
        galleryIntent.SetAction(Intent.ActionGetContent);
        this.StartActivityForResult(Intent.CreateChooser(galleryIntent, "Please choose photo to insert"), 0);
    }

 protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        if (resultCode == Result.Ok)
        {
         System.IO.Stream stream = ContentResolver.OpenInputStream(data.Data);
            Bitmap bitmap = DecodeBitmapFromStream(data.Data, 75, 50);
  //  DecodeBitmapFromStream is the code to take the image from stream. Please refer below separately
            MemoryStream memStream = new MemoryStream();
            bitmap.Compress(Bitmap.CompressFormat.Webp, 100, memStream);
            prodPic = memStream.ToArray(); //variable prodPic assigned here
            //The commented lines below are to check if prodPic has really got the value and it worked well.
/*            MemoryStream ms4Pic = new MemoryStream(prodPic);
            Bitmap bmp = BitmapFactory.DecodeStream(ms4Pic);
            imgProdPic.SetImageBitmap(bmp); */
        }
    }

BItmap is decoded from stream as follows

private Bitmap DecodeBitmapFromStream(Android.Net.Uri data, int requestedWidth, int requestedHeight)
    {
        System.IO.Stream stream = ContentResolver.OpenInputStream(data);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.InJustDecodeBounds = true;
        BitmapFactory.DecodeStream(stream);
        options.InSampleSize = CalculateInSampleSize(options, requestedWidth, requestedHeight);
        stream = ContentResolver.OpenInputStream(data);
        options.InJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.DecodeStream(stream, null, options);
        return bitmap;
    }

I got CalculateInSampleSize from the internet to reduce file size but the app still crashes if the image is bigger than 10kb. The code is as follows

   private int CalculateInSampleSize(BitmapFactory.Options options, int requestedWidth, int requestedHeight)
    {
        int height = options.OutHeight;
        int width = options.OutWidth;
        int inSampleSize = 1;
        if (height > requestedHeight || width > requestedWidth)
        {
            int halfHeight = height / 2;
            int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > requestedHeight && (halfWidth / inSampleSize) > requestedWidth)
            {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

The wcf code that takes this is

contract

[OperationContract]
[WebInvoke(Method = "POST")]
int Post4Free(string title, string category, string subcategory, string prodcategory, string price, string description, byte[] prodPic);

Code

  public int Post4Free(string title, string category, string subcategory, string prodcategory, string price, string description, byte[] prodPic)
    {
//System.IO.StreamWriter fl2 = new System.IO.StreamWriter(@"C:\abc\sukLog2.txt");
        //fl2.WriteLine(title); 
        //fl2.Close();
 //The above 3 lines were first added to check if the call reached here for the small as well as for the bigger pictures. For the small, it reaches here and for the bigger, poof - it crashes and never reaches here.
        int checker;
        string id = AdminBaseUIPage.GetID("ProdTable");
        string sql = "Insert into ProdTable (Id,ProdTitle, ProdCategory, ProdSubCategory, ProdProdCategory, ProdPrice, ProdDetail, ProdPic, DatePosted, Status)" +
            "values (@Id, @ProdTitle, @ProdCategory, @ProdSubCategory, @ProdProdCategory, @ProdPrice, @ProdDetail, @ProdPic, @DatePosted, @Status)";
        SqlCommand command = new SqlCommand(sql, Connection);
        command.Parameters.AddWithValue("@Id", id); 
        command.Parameters.AddWithValue("@ProdTitle", title);
        command.Parameters.AddWithValue("@ProdCategory", category);
        command.Parameters.AddWithValue("@ProdSubCategory", subcategory);
        command.Parameters.AddWithValue("@ProdProdCategory", prodcategory);
        command.Parameters.AddWithValue("@ProdPrice", price);
        command.Parameters.AddWithValue("@ProdDetail", description);
        command.Parameters.AddWithValue("@ProdPic", prodPic);
        command.Parameters.AddWithValue("@DatePosted", DateTime.Now.ToString());
        command.Parameters.AddWithValue("@Status", "A");
//The AddWithValue methods will be changed later.
        checker = DataManage.ExecuteNonQuery(command);
        return checker;
    }

I tried my best to find a solution online and the best thing most suggest is the CalculateInSampleSize which does not give me a solution. Thus, I am either interested in a solution which makes the size of the pic from gallery less than 10kb or which makes the app stop crashing even when file size is bigger than 10kb. Thank you very much in advance for your cooperation as it would end my sleepless nights.


Solution

  • Finally it worked after adding the following lines to the web.config of the service (wcf) within system.serviceModel. Actually its not a must to set it at 64000000. You can choose your desired size.

      <bindings>
        <basicHttpBinding>
           <binding maxBufferSize="64000000" maxReceivedMessageSize="64000000" /> 
        </basicHttpBinding> 
     </bindings>