OneDrive Upload/Download to Specified Directory

YnotDraw picture YnotDraw · May 17, 2014 · Viewed 7.3k times · Source

I'm trying to use the Live SDK (v5.6) to include backup/restore from OneDrive in my Windows Phone 8.1 Silverlight application. I can read/write to the standard "me/skydrive" directory, but I am having a horrible time in finding a way to upload/download to a specified directory. I can create the folder if it doesn't exist no problem.

I have been trying below with no luck.

var res = await _client.UploadAsync("me/skydrive/mydir", fileName, isoStoreFileStream, OverwriteOption.Overwrite);

I've also tried getting the directory ID and passing that in also.

var res = await _client.UploadAsync("me/skydrive/" + folderId, fileName, isoStoreFileStream, OverwriteOption.Overwrite);

Same error.. I receive 'mydir' or the id isn't supported...

"{request_url_invalid: Microsoft.Live.LiveConnectException: The URL contains the path 'mydir', which isn't supported."

Any suggestions? If you suggest an answer for the uploadasync, could you also include how I could download my file from the specified directory? Thanks!

Answer

Ertay Shashko picture Ertay Shashko · May 17, 2014

Here's an extension method that checks if a folder is created and:

  1. If created returns the folder id.
  2. If not created, creates it and returns the folder id.

You can then use this id to upload to and download from that folder.

public async static Task<string> CreateDirectoryAsync(this LiveConnectClient client,
string folderName, string parentFolder)
    {
        string folderId = null;

        // Retrieves all the directories.
        var queryFolder = parentFolder + "/files?filter=folders,albums";
        var opResult = await client.GetAsync(queryFolder);
        dynamic result = opResult.Result;

        foreach (dynamic folder in result.data)
        {
            // Checks if current folder has the passed name.
            if (folder.name.ToLowerInvariant() == folderName.ToLowerInvariant())
            {
                folderId = folder.id;
                break;
            }
        }

        if (folderId == null)
        {
            // Directory hasn't been found, so creates it using the PostAsync method.
            var folderData = new Dictionary<string, object>();
            folderData.Add("name", folderName);
            opResult = await client.PostAsync(parentFolder, folderData);
            result = opResult.Result;

            // Retrieves the id of the created folder.
            folderId = result.id;
        }

        return folderId;
    }

You then use this as:

string skyDriveFolder = await CreateDirectoryAsync(liveConnectClient, "<YourFolderNameHere>", "me/skydrive");

Now skyDriveFolder has the folder id that you can use when uploading and downloading. Here's a sample Upload:

LiveOperationResult result = await liveConnectClient.UploadAsync(skyDriveFolder, fileName,
                                                  fileStream, OverwriteOption.Overwrite);

ADDITION TO COMPLETE THE ANSWER BY YnotDraw

Using what you provided, here's how to download a text file by specifying the file name. Below does not include if the file is not found and other potential exceptions, but here is what works when the stars align properly:

public async static Task<string> DownloadFileAsync(this LiveConnectClient client, string directory, string fileName)
    {
        string skyDriveFolder = await OneDriveHelper.CreateOrGetDirectoryAsync(client, directory, "me/skydrive");
        var result = await client.DownloadAsync(skyDriveFolder);

        var operation = await client.GetAsync(skyDriveFolder + "/files");

        var items = operation.Result["data"] as List<object>;
        string id = string.Empty;

        // Search for the file - add handling here if File Not Found
        foreach (object item in items)
        {
            IDictionary<string, object> file = item as IDictionary<string, object>;
            if (file["name"].ToString() == fileName)
            {
                id = file["id"].ToString();
                break;
            }
        }

        var downloadResult= await client.DownloadAsync(string.Format("{0}/content", id));

        var reader = new StreamReader(downloadResult.Stream);
        string text = await reader.ReadToEndAsync();
        return text;
    }

And in usage:

var result = await DownloadFile(_client, "MyDir", "backup.txt");