How to download file from SkyDrive using REST API SDK? (Windows Store app, http_client)

May 17, 2013 at 1:26 PM
Hello.
I am trying to download file from SkyDrive using web::http::client::http_client.
std::wstring fileID = std::wstring (file_id);
    
    Platform::String ^fName = Platform::String::Concat (ref new Platform::String (L"Users\\"), ref new Platform::String (file_name));

    create_task (Windows::Storage::ApplicationData::Current->TemporaryFolder->CreateFileAsync (fName, Windows::Storage::CreationCollisionOption::ReplaceExisting))
    .then ([fileID] (StorageFile ^userSave)
    {
        file_stream <unsigned char>::open_istream (userSave, std::ios_base::out)
        .then ([fileID] (basic_istream <unsigned char> fileStream)
        {
            http_client client (SkyDriveHost);
            
            std::wstring request (fileID.c_str ());
            request.append (L"/content?download=true&access_token=");
            request.append (token);

            client.request (methods::GET, request, fileStream, 1052004, L"application/octet-stream")
            .then ([fileStream] (http_response response)
            {
                fileStream.close ();
            });
        });
    });
But I always get an exception after client.request.
Please, point me what I am doing wrong.
May 17, 2013 at 3:41 PM
Hello hellobody,

If I understand you intent, you want to store the data from SkyDrive in 'fSTream', which means that you need to create an ostream (one that can be written to) instead of an istream. Also, your code is currently using the stream as the source of the body of the GET, which will be rejected. Instead, you would want to use the ostream as the target of the response message. Instead of using the convenience version of request() that takes the method, etc., construct an http_request instance and set the response stream. Then, pass the request object to request().

BTW, I'm working on a sample on how to connect to Windows Live that I'll probably get up sometime next week, if nothing else gets in the way.

Niklas
May 18, 2013 at 8:50 AM
Thanks for the reply.

Now I am trying to do things considering your instructions, but I've faced new problem: I don't understand how to set 'path_query_fragment' parameter to client request.
std::wstring fileID = std::wstring (file_id);
    
    Platform::String ^fName = Platform::String::Concat (ref new Platform::String (L"Users\\"), ref new Platform::String (file_name));

    create_task (Windows::Storage::ApplicationData::Current->TemporaryFolder->CreateFileAsync (fName, Windows::Storage::CreationCollisionOption::ReplaceExisting))
    .then ([fileID] (StorageFile ^userSave)
    {
        file_stream <unsigned char>::open_ostream (userSave, std::ios_base::out)
        .then ([fileID] (basic_ostream <unsigned char> fileStream)
        {
            http_client client (SkyDriveHost);
            
            std::wstring path_query_fragment (fileID.c_str ());
            path_query_fragment.append (L"/content?download=true&access_token=");
            path_query_fragment.append (token);

            http_request request (methods::GET);
            request.set_response_stream (fileStream);

            //I can't find a place where I can pass path_query_fragment, which is abligatory to set file that I want to download
            
            client.request (request)
            .then ([fileStream] (http_response response)
            {
                fileStream.close ();
            });
        });
    });
May 20, 2013 at 2:38 AM
Edited May 20, 2013 at 2:38 AM
Use this method on the request object:
    void set_request_uri(const uri& uri);
In fact, it's usually easier to use the uri_builder class to create the uri, which you then convert to a uri instance, than to use string manipulation.

Niklas
May 20, 2013 at 6:36 AM
OK, thank you.
Coordinator
May 20, 2013 at 6:12 PM
You also can use the 'request' helper methods if you want as well. Here is one overload which takes the path, query, and fragment portions of the request uri:
    /// <summary>
    /// Asynchronously sends an HTTP request.
    /// </summary>
    /// <param name="mtd">HTTP request method.</param>
    /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's base URI.</param>
    /// <returns>An asynchronous operation that is completed once a response from the request is received.</returns>
    pplx::task<http_response> request(method mtd, const utility::string_t &path_query_fragment)
Steve
May 25, 2013 at 3:33 PM
Edited May 25, 2013 at 3:34 PM
By the way, the Windows Live sample is now in the source tree, under Release/collateral/Samples/WindowsLiveAuth.
May 27, 2013 at 7:08 AM
Thanks, I'll look at your sample. Maybe it helps me too.
May 28, 2013 at 4:13 PM
Please do, and let us know if you think there are ways to improve its usefulness!
Oct 16, 2013 at 5:42 PM
Edited Oct 16, 2013 at 5:42 PM
Hello, I couldn't open the WindowsLiveAuth sample project, there is no .sln. How can I do that, please? Thank you!
Coordinator
Oct 16, 2013 at 7:27 PM
Did you try opening the WindowsLiveAuth project file from Visual Studio: Release/collateral/Samples/WindowsLiveAuth/WindowsLiveAuth.vcxproj ?
This should open with VS2012.
Oct 17, 2013 at 6:20 PM
Hi Kavyavo,
Yes I did, but visual studio couldn't find some properties. Then I changed the paths inside of the vcxproj and it worked fine.
Now my doubt is: what is the right url to download a file? I am using

"https://apis.live.net/V5.0/me/skydrive/files/helloworld.txt/content?access_token=EwBAAq1DBAAUG...end of token"

and I am getting The URL contains the resource 'content', which isn't supported.

Thank you!
Coordinator
Oct 19, 2013 at 2:04 AM
From the error message, it looks like the URL is not right.
As per the Live REST API documentation on msdn,
"To download the content of a File resource, make a GET request to/FILE_ID/content. The file content is returned in the response body."

Try providing the FILE_ID instead of the file name (helloworld.txt) and see if it works.

Kavya