locked
How to the get the original file in order to send it over a WinJS.xhr PUT?

    Question

  • Hi all, simple (newby) question here.

    I have the url to a blob (file) in my app. I got the file from the camera and then used the URL.createObjectURL in order to show the image as the src of an img.

    So now I have to save that to the server so I need to get the original file and add it as data to the WinJS.xhr PUT I want to make. I guess there's actually two questions.

    1) How do I get the actual file object from its url?

    2) Once I have it, how do I 'attach' it as body of my PUT.

    Thanks in advance,

    Sebastián

    p.s: not only newby to WinJS, as we all are, but also a newby to js :)


    http://bit.ly/sebagomez

    Thursday, July 12, 2012 1:09 AM

Answers

  • Hi,

    I would like to suggest you to try this:
     
                Windows.Storage.StorageFile.getFileFromPathAsync(fileToUpload)
                .then(function (file) {
                    return file.openAsync(Windows.Storage.FileAccessMode.read);
                })
                .then(function (fileStream) {
                    var blob = MSApp.createBlobFromRandomAccessStream("your content type", fileStream);
                    WinJS.xhr({
                        url: your request url,
                        type: "PUT",
                        headers: any headers you need,
                        data: blob
                    })
                    .done(function () {
                    });
                });

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework

    Wednesday, July 18, 2012 10:55 AM
    Moderator

All replies

  • To get an IStorageFile from an URL, you can use http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.storagefile.createstreamedfilefromuriasync.aspx

    See this thread for an example on how to use the BackgroundUploader to upload a file using a POST request, PUT should work all the same:

    http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/8daa2e5d-5d4d-4102-857d-9c2329b7d535

    Thursday, July 12, 2012 8:38 AM
  • Thanks!

    One question, why can't I use WinJS.xhr instead of the background uploader? I mean, can I still use xhr?


    http://bit.ly/sebagomez

    Thursday, July 12, 2012 2:19 PM
  • So I guess I wasn't clear enough.

    The url to the file I have looks like this: blob:4ECBCBBF-435B-4519-96BD-ED432D3A34DC. 

    So this is what I got:

    var blobUri = new Windows.Foundation.Uri(strUri);
    var thumbnail = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(blobUri);
    Windows.Storage.StorageFile.createStreamedFileFromUriAsync('temp.png', blobUri, thumbnail))

    where strUri is where the above uri is set. But when I execute that I get a error saying:"JavaScript runtime error: The parameter is incorrect"

    What am I doing wrong? 


    http://bit.ly/sebagomez

    Thursday, July 12, 2012 4:46 PM
  • Oh sorry, I mixed that up somewhat. I would propose using BackgroundUploader somewhat like this (pseudo code, CoffeeScript style, since it's late and I'm too lazy to fire up the Studio ;)).

    streamReference = RandomAccessStreamReference.createFromUri(blobUri)

    streamReference.openReadAsync()
      .then (sourceStream) ->
        uploader = new BackgroundUploader
        uploader.method = 'PUT'
        # set serverCredential as needed
        uploader.createUploadFromStreamAsync(targetUri, sourceStream)
      .then ->
        # yay! done!

    Thursday, July 12, 2012 9:35 PM
  • Btw, if you prefer to use WinJS.xhr, you could also create a DataReader from the IRandomAccessStream, do a readBytes() and pass the unsigned byte array to the XMLHttpRequest::send - it should work according to the docs...
    Thursday, July 12, 2012 9:43 PM
  • Thanks Marcus, I will try that and let you know how it goes.

    I do have a question, regarding the BackgroundUploader you suggested. Every where I look the same background uploader is suggested, why is that? why is the BackgroundUploader better tham WinJS.xhr?


    http://bit.ly/sebagomez

    Saturday, July 14, 2012 6:41 PM
  • Hi,

    You can use xhr to send binary data. To do this, first create a blob. Below is a sample from Lindsay of the product team:
     
    var blob = MSAPP.createBlobFromRandomAccessStream("your content type", stream);
    xhr.send(blob);

      >> Every where I look the same background uploader is suggested, why is that?

    Using xhr to send small files is fine. But if you need to send large files, it is recommended to use background file upload, as it takes care of a lot of works, such as divide the file to smaller pieces, retry a failed request, pause, resume, and so on. But usually small files do not benifit from those features, and using xhr is easier than background uploader as you can write less code.

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework


    Monday, July 16, 2012 4:46 PM
    Moderator
  • Thanks for clarifying MingXu, that really helped a lot.

    The proble I'm facinf now is still the one that motivated my post. Marcus code does not seem to work... or I might be missing something.

    var uri = Windows.Foundation.Uri(auxColl[i].data);
    var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(uri);
    streamRef.openReadAsync()
    .done((function (file) {
    	var blob = window.MSApp.createBlobFromRandomAccessStream("image/png", file);

    this is what I have but is is not working. I get a 'Not Implemented' Excpetion.

    Please help, is the only part I'm missing :(

    Thanks


    http://bit.ly/sebagomez

    EDIT: while debugging I got the following message on an internal function "[Status is 'error', but getResults did not return an error,Missing or invalid status parameter passed to completed handler,Missing or invalid sender parameter passed to completed handler]"
    Monday, July 16, 2012 8:56 PM
  • Hi,

    I don't have a camera at hand. So I'm not very sure if you can create a Uri using a camera. However, according to http://msdn.microsoft.com/en-us/library/windows/apps/hh465152.aspx, you can save the captured photo to a local file by calling captureFileAsync. Then you can create a random access stream using the file, and use the above code to create a blob. Something like:
     
                file.openAsync(Windows.Storage.FileAccessMode.read)
                .then(function (stream) {
                    var blob = MSApp.createBlobFromRandomAccessStream("your content type", stream);
     
     

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework

    Tuesday, July 17, 2012 10:42 AM
    Moderator
  • Hi Sebastian,

    if you want to use WinJS.xhr, loading the data from the stream into a byte array should be enough.

      streamReference = RandomAccessStreamReference.createFromUri(blobUri);
    
      streamReference.openReadAsync().then(function(sourceStream) {
        var dataReader;
        dataReader = new Windows.Storage.Streams.DataReader(sourceStream);
        return dataReader.loadAsync(dataReader.unconsumedBufferLength).then(function() {
          var byteData;
          byteData = dataReader.readBytes();
          return xhr.send(byteData);
        });
      });
    

    Also my advice would be to always use separate completion and error handlers on promise continuations - i.e. then(complete, error, progress) instead of done(handler). In most cases you will either want to handle any eventual errors (and not try to continue anyway) or pass them on to the parent promise/function so it can be handled there.

    Tuesday, July 17, 2012 12:09 PM
  • is blobUri of the form BLOB:XXXXXXXXX?

    Cause that's my url and i can't get this sample to work :(


    http://bit.ly/sebagomez

    Tuesday, July 17, 2012 11:16 PM

  • byteData = dataReader.readBytes();


    I get an error saying readBytes needs an array as argument :(


    http://bit.ly/sebagomez

    Tuesday, July 17, 2012 11:39 PM

  • byteData = dataReader.readBytes();


    I get an error saying readBytes needs an array as argument :(


    http://bit.ly/sebagomez

    Now that's strange. I admit I was wondering why the DataReader::ReadBytes method documentation showed another signature for JavaScript than for C++ but assumed that was done intentionally.

    Could you try someting along the lines of:

    var data = new Uint8Array();
    dataReader.readBytes(data);

    Wednesday, July 18, 2012 8:37 AM
  • Hi,

    I would like to suggest you to try this:
     
                Windows.Storage.StorageFile.getFileFromPathAsync(fileToUpload)
                .then(function (file) {
                    return file.openAsync(Windows.Storage.FileAccessMode.read);
                })
                .then(function (fileStream) {
                    var blob = MSApp.createBlobFromRandomAccessStream("your content type", fileStream);
                    WinJS.xhr({
                        url: your request url,
                        type: "PUT",
                        headers: any headers you need,
                        data: blob
                    })
                    .done(function () {
                    });
                });

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework

    Wednesday, July 18, 2012 10:55 AM
    Moderator
  • Hi all, as suggested here I moved to the BackgroundUploader and everything is running now.

    When I did the last thing that Marcus suggested the post was sending just numbers so on the server side a plaint text file was created with it's numbers (bytes) in it (weird).

    So everything is ok now, thanks all for your help. The lack of documentation and sometimes wrong is really frustrating... I guess this is what I get for being so early on Win 8 development. I have to say, the SDK samples are very good and helpful... they do go over a ton of cool features.

    Best regards


    http://bit.ly/sebagomez

    Thursday, July 19, 2012 7:30 PM
  • Thanks for clarifying MingXu, that really helped a lot.

    The proble I'm facinf now is still the one that motivated my post. Marcus code does not seem to work... or I might be missing something.

    var uri = Windows.Foundation.Uri(auxColl[i].data);
    var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(uri);
    streamRef.openReadAsync()
    .done((function (file) {
    	var blob = window.MSApp.createBlobFromRandomAccessStream("image/png", file);

    this is what I have but is is not working. I get a 'Not Implemented' Excpetion.

    Please help, is the only part I'm missing :(

    Thanks


    http://bit.ly/sebagomez

    EDIT: while debugging I got the following message on an internal function "[Status is 'error', but getResults did not return an error,Missing or invalid status parameter passed to completed handler,Missing or invalid sender parameter passed to completed handler]"

    Hi, how did you fix  'Not Implemented' Excpetion ?
    Saturday, September 15, 2012 11:58 PM
  • is blobUri of the form BLOB:XXXXXXXXX?

    Cause that's my url and i can't get this sample to work :(


    http://bit.ly/sebagomez

    Yes, my blobUri of the form BLOB:XXXXXXXXX.  So how did you fix 'Not Implemented' Excpetion which is returned by streamReference.openReadAsync()?

    Saturday, September 15, 2012 11:59 PM