1
votes

Since all my other messages will be JSON I thought I would convert my android solution to send images, taken from the camera to a WCF service using JSON multipart messages. I think I have the sending working but do not know how to deserialize. The reason I do not base64 encode is that I want android 2.1 to work and base64 encoding does not work(at least that is what I have read, and the only "hack" I have found only work for small files).

So in android I try to send the image:

public void upload() throws Exception {
    //Url of the server
    String url = "http://192.168.0.10:8000/service/UploadImage";
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(url);
    MultipartEntity mpEntity = new MultipartEntity();
    //Path of the file to be uploaded
    String filepath = path;
    File file = new File(filepath);
    ContentBody cbFile = new FileBody(file, "image/jpeg");     

    //Add the data to the multipart entity
    mpEntity.addPart("image", cbFile);
    post.setEntity(mpEntity);
    //Execute the post request
    HttpResponse response1 = client.execute(post);
    //Get the response from the server
    HttpEntity resEntity = response1.getEntity();
    String Response=EntityUtils.toString(resEntity);
    Log.d("Response:", Response);

    client.getConnectionManager().shutdown();
}

The wcf(as it was when I send using httpurlconnect and outputstream from android) code. It was working then :D:

public string UploadImage(Stream image)
    {
        var buf = new byte[1024];
        var path = Path.Combine(@"c:\tempdirectory\", "test.jpg");
        int len = 0;
        using (var fs = File.Create(path))
        {
            while ((len = image.Read(buf, 0, buf.Length)) > 0)
            {
                fs.Write(buf, 0, len);
            }
        }
        return "hej";
    }  

Interface for the wcf [OperationContract] [WebInvoke( Method = "POST", UriTemplate = "/UploadImage", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] string UploadImage(Stream image);

And if it matters, the consoleapplication that runs the wcf

   static void Main(string[] args)
    {
        string baseAddress = "http://192.168.0.10:8000/Service";
        ServiceHost host = new ServiceHost(typeof(ImageUploadService), new Uri(baseAddress));
        WebHttpBinding binding = new WebHttpBinding();
        binding.MaxReceivedMessageSize = 4194304;

        host.AddServiceEndpoint(typeof(IImageUploadService),binding , "").Behaviors.Add(new WebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");
        Console.ReadKey(true);
    }

So now to the question, how do I parse the incomming JSON stream? Is there a better way to do it?

Note: I tried setting up fiddler but after 3 hours not getting it to even read the traffic, I gave ut.

Is there a good way to actually debug this code?

Forgot to include the result if I convert the stream to byte array and save that to file:

--IZZI8NmDZ-Id7DWP5z0nuPPZspVAGglcfEY9
    Content-Disposition: form-data; name="image"; filename="mypicture.jpg"
    Content-Type: image/jpeg
    Content-Transfer-Encoding: binary

   ÿØÿá°Exif and other funny letters of cause :D ending with
   --IZZI8NmDZ-Id7DWP5z0nuPPZspVAGglcfEY9--

With some new code I can manage to get this

--crdEqve1GThGGKugB3On0tGNy5h2u746
Content-Disposition: form-data; name="entity"

{"filename":"mypicture.jpg"}
--crdEqve1GThGGKugB3On0tGNy5h2u746
Content-Disposition: form-data; name="file"; filename="mypicture.jpg"
Content-Type: application/octet-stream

ÿØÿá´Exif and the whole image here ...

The new update routine looks like this:

public void uploadFile() {
         String filepath = path;
            File file = new File(filepath);
        HttpClient httpClient = new DefaultHttpClient();

        HttpPost postRequest = new HttpPost("http://192.168.0.10:8000/service/UploadImage");
        ResponseHandler<String> responseHandler = new BasicResponseHandler();

        // Indicate that this information comes in parts (text and file)
        MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

        try {

            //Create a JSON object to be used in the StringBody
            JSONObject jsonObj = new JSONObject();

            //Add some values
            jsonObj.put("filename", file.getName());

            //Add the JSON "part"
            reqEntity.addPart("entity", new StringBody(jsonObj.toString()));
        }
        catch (JSONException e) {
            Log.v("App", e.getMessage());
        }
        catch (UnsupportedEncodingException e) {
            Log.v("App", e.getMessage());
        }

        FileBody fileBody = new FileBody(file);//, "application/octet-stream");
            reqEntity.addPart("file", fileBody);

            try {
                postRequest.setEntity(reqEntity);

                 //Execute the request "POST"
            HttpResponse httpResp = httpClient.execute(postRequest);

            //Check the status code, in this case "created"
            if(((HttpResponse) httpResp).getStatusLine().getStatusCode() == HttpStatus.SC_CREATED){
                Log.v("App","Created");
            }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

Still I need a way to separate the the different part of the streams so I can divide the json message part(if I need those) and then get the bytearray for the image as a seperate part to store. I guess I could just skip json and go back to my original of JUST sending the bytearray of the image, but well I will need to be able to handle JSON messages anyways so.

Thanks for the comments so far.

1

1 Answers

1
votes

My first thought is that it isn't a JSON stream. It is probably a byte-stream. Also, if your image is larger than 1024 bytes, you will infinitely read and write the first 1024 bytes. You should have an offset variable that tracks how much you have read and starts reading after that.