.NET Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

SkyDrive Sync on Windows Phone - Uploading Content To SkyDrive

09.07.2013
| 2218 views |
  • submit to reddit
If you have missed the previous three articles in the series, you should definitely read those:

In this article, I am going to show you how to upload content to SkyDrive once all the files have been added to the reference list on the device.

First and foremost, we need a way to trigger the synchronization process. To do that, let's add an application bar menu item:

<shell:ApplicationBarMenuItem Text="sync" Click="ApplicationBarMenuItem_Click"></shell:ApplicationBarMenuItem>

Now we need to make sure that two conditions are met when the action is triggered:

  1. The user is already authenticated and there is a session token available.
  2. There are files to actually sync.

All-in-all, here is what it would look like:

private async void ApplicationBarMenuItem_Click(object sender, EventArgs e)
{
    if (_currentSession != null && FileReferences.Count > 0)
    {
        string folderId = await CreateRootFolder(_currentSession);
    }
}

If the pre-conditions pass, I am attempting to create a root folder, where all files will be pushed. If the folder already exists, the function (described in the first article) will return the ID for it.

Now, let's upload the files. I have a helper function that will handle this task - it relies on the UploadAsync function that is already implemented via the Live SDK:

public static async Task<bool> UploadFile(LiveConnectSession session, Stream fileStream, string targetFolder, string name)
{
    try
    {
        LiveConnectClient client = new LiveConnectClient(session);
        LiveOperationResult result = await client.UploadAsync(targetFolder, name, fileStream, OverwriteOption.Overwrite);

        return true;
    }
    catch
    {
        return false;
    }
}

Notice that in order to make the process more streamlined, I am passing the content that needs to be uploaded as a stream rather than a direct reference (such as StorageFile or ExternalStorageFile).

Because of different ways different storage targets are handled, I have also created a helper function that would give me a reference point for all stream types - local storage (both isolated and gallery) as well as external:

internal async Task<Stream> GetFileStream(FileReference file)
{
    if (file.FileType == FileType.ExternalStorage)
    {
        Debug.WriteLine("DEALING with EXTERNAL");

        // Dealing with external storage files.
        ExternalStorageDevice device = (await ExternalStorage.GetExternalStorageDevicesAsync()).FirstOrDefault();

        if (device != null)
        {
            ExternalStorageFile extFile = await device.GetFileAsync(file.Token);

            if (extFile != null)
            {
                return await extFile.OpenForReadAsync();
            }
            else
            {
                return null;
            }
        }
        else
        {
            return null;
        }

    }
    else if (file.FileType == FileType.LocalAlbum)
    {
        Debug.WriteLine("DEALING with GALLERY");
        // Dealing with a file in a local gallery.

        return GetGalleryPictureStream(file.Token, file.Name);
    }
    else
    {
        // Dealing with a local file.
        StorageFolder folder = await ApplicationData.Current.LocalFolder.GetFolderAsync("SyncStorage");
        StorageFile stFile = await folder.GetFileAsync(file.Name);

        return await stFile.OpenStreamForReadAsync();
    }
}

StorageFile and ExternalStorageFile give the developer a one-liner way to access the stream. With gallery photos, the approach is a bit different. And once again, there is a helper function that accomplishes what I want with the help of the XNA MediaLibrary class.

internal static Stream GetGalleryPictureStream(string albumName, string pictureName)
{
    Stream stream = null;

    MediaLibrary library = new MediaLibrary();

    var pictureAlbum = (from c in library.RootPictureAlbum.Albums where c.Name == albumName select c).FirstOrDefault();
    if (pictureAlbum != null)
    {
        foreach (var pic in pictureAlbum.Pictures)
        {
            Debug.WriteLine(pic.Name);
        }

        Picture photoToSend = (from p in pictureAlbum.Pictures where p.Name == pictureName select p).FirstOrDefault();

        if (photoToSend != null)
            stream = photoToSend.GetImage();
    }

    return stream;
}

Back to the sync menu item, we can now iterate through the file reference list and process the upload:

private async void ApplicationBarMenuItem_Click(object sender, EventArgs e)
{
    if (_currentSession != null && FileReferences.Count > 0)
    {
        string folderId = await CreateRootFolder(_currentSession);

        foreach (var file in FileReferences)
        {
            await UploadFile(_currentSession, await GetFileStream(file), file.Name, folderId);
        }
    }
}

The files will be shown on SkyDrive, inside the SYNCFOLDER directory once the upload is completed: