How to save Isolated Storage's files to SkyDrive (CSWP8BackupToSkyDrive)

Introduction

This sample demonstrates how to save Isolated Storage's files to SkyDrive. ​We can backup our Windows Phone Isolated Storage data to SkyDrive using Live Connect API.

In this scenario I used "Camera Capture" feature of WP to capture camera image, save it to Isolated Storage and upload it to dedicated SkyDrive folder. We can replace the picture with the other supported types.

Building the Sample

To run this sample, you need "Live SDK" and "Async live Connect SDK". You can install them by using NuGet: type "live" as key words and then they will appear in the list of search results.

Running the Sample

Step 1:               Open the "CSWP8BackupToSkyDrive.sln."

Step 2:               Press Ctrl+F5. You will see the emulator looks like this:

Step 3:               Click the "Show Camera" button to capture an image.

Step 4:               Then click the "Sign in" button, User is redirected to Windows Live authentication page:

Step 5:               User is prompt to okay scopes that your application needs:

Step 6:               When the "Yes" is clicked, the emulator looks like this:

Step 7:               Locate to SkyDrive, my SkyDrive as shown below:

Step 8:               Click the Backup button and then click OK. The emulator looks like this:

Step 9:               When the backup is complete, the emulator looks like this:

Step 10:            Then refresh the SkyDrive. You can see a folder named IsolatedStorageFolder already created; open the folder, you will see the image just taken.

Step 11:            The validation is complete.

Using the Code

Step 1:               Create a C# "Windows Phone App" in Visual Studio 2012 or Visual Studio Express 2012 for Windows Phone. Name it as "CSWP8BackupToSkyDrive."

Step 2:               [Note]Before you continue with your development and call Live Connect APIs, you must configure your app with a unique identifier, which we call a client ID. You get a client ID and you can specify a redirect domain (if needed), at the Live Connect app management site. Sign in with your Microsoft account credentials, click Create application, type the app's name and then click I accept. Live Connect creates and then displays the client ID. It should look something like this 00000000480E7666:

Step 3:               In the XAML editor, in the <phone> tag, with the other namespace declarations, add the following code to main app page:

XAML
Edit|Remove
xmlns:my="clr-namespace:Microsoft.Live.Controls;assembly=Microsoft.Live.Controls"

 

Step 4:                The XAML code in MainPage.xaml will resemble the following:

XAML
Edit|Remove
<!--LayoutRoot is the root grid where all page content is placed-->
   <Grid x:Name="LayoutRoot" Background="Transparent">
       <Grid.RowDefinitions>
           <RowDefinition Height="Auto"/>
           <RowDefinition Height="*"/>
       </Grid.RowDefinitions>


       <Image x:Name="cameraImage" Height="400" Width="480" />


       <!--Button StackPanel to the right of viewfinder>-->
       <Grid x:Name="ContentPanel" Grid.Row="1" Grid.Column="1" Margin="12,0,12,0">
           <StackPanel>
               <Button x:Name="btnShowCamera" Content="Show Camera"  FontSize="26" FontWeight="ExtraBold" Height="75" Click="btnShowCamera_Click" />
               <!--CHANGE ClientId to your own client ID. Leave the rest the same-->
               <my:SignInButton Name="btnSignIn"/>
               <Button x:Name="btnBackup" Click="btnBackup_Click" Content="Backup" IsEnabled="False" />
               <TextBlock x:Name="tbDate" TextWrapping="Wrap" Margin="12, 30, 12, 12"/>
           </StackPanel>
       </Grid>


       <!--Used for debugging >-->
       <TextBlock Height="40" HorizontalAlignment="Left" Margin="8,428,0,0" Name="tbDebug" VerticalAlignment="Top" Width="626" FontSize="24" FontWeight="ExtraBold" />
   </Grid>

 

Step 5:               Statement required fields in front of the constructor.

C#
Edit|Remove
CameraCaptureTask cameraCaputreTask = null;                     //CameraCaptureTask instance.
       private LiveConnectClient client = null;
       private LiveConnectSession session = null;
       private string strSkyDriveFolderName = "IsolatedStorageFolder"; // The folder name for backups
       private string strSkyDriveFolderID = string.Empty;              // The id of the folder name for backups
       private string fileID = null;                                   // The file id of your backup file
       private IsolatedStorageFileStream readStream = null;            // The stream for restoring data 
       private string fileName = "MyAppBackup.jpg";                    // Backup name for the capture image.  

 

Step 6:               In the constructor, we will set the SignIn button and initialize CameraCaptureTask.

C#
Edit|Remove
public MainPage()
       {
           InitializeComponent();


           // SignIn button
           btnSignIn.ClientId = "00000000480E7666";
           btnSignIn.Scopes = "wl.basic wl.signin wl.offline_access wl.skydrive_update";
           btnSignIn.Branding = BrandingType.Windows;
           btnSignIn.TextType = ButtonTextType.SignIn;
           btnSignIn.SessionChanged += btnSignIn_SessionChanged;


           // CameraCaptureTask
           cameraCaputreTask = new CameraCaptureTask();
           cameraCaputreTask.Completed += cameraCaputreTask_Completed;
       }

 

Step 7:               For the capture feature, we will use the CameraCaptureTask.  We use a button to launch the CameraCaptureTask and save the intercepted image to Isolated Storage.

C#
Edit|Remove
private void btnShowCamera_Click(object sender, RoutedEventArgs e)
      {
          cameraCaputreTask.Show();
      }


      /// <summary>
      /// Processing when the chooser task is completed.
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      void cameraCaputreTask_Completed(object sender, PhotoResult e)
      {
          if (e.TaskResult == TaskResult.OK)
          {
              try
              {
                  // Create a BitmapImage.
                  BitmapImage bitmap = new BitmapImage();
                  bitmap.SetSource(e.ChosenPhoto);
                  // Display the image.
                  cameraImage.Source = bitmap;


                  // Write message to the UI thread.
                  UpdateUIThread(tbDebug, "Captured image available, saving picture.");


                  // Save picture as JPEG to isolated storage.
                  using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
                  {
                      Uri uri = new Uri(fileName, UriKind.Relative);
                      string strTempFile = uri.ToString();


                      if (isStore.FileExists(strTempFile))
                      {
                          isStore.DeleteFile(strTempFile);
                      }


                      using (IsolatedStorageFileStream targetStream = isStore.OpenFile(strTempFile, FileMode.Create, FileAccess.Write))
                      {
                          WriteableBitmap wb = new WriteableBitmap(bitmap);
                          // Encode WriteableBitmap object to a JPEG stream.
                          Extensions.SaveJpeg(wb, targetStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
                      }
                  }


                  // Write message to the UI thread.
                  UpdateUIThread(tbDebug, "Picture has been saved to isolated storage.");
              }
              finally
              {
                  // Close image stream
                  e.ChosenPhoto.Close();
              }
          }
      }

 

Step 8:               For SignIn button, first we will handle the event when SkyDrive sign in status is changed. And then we will get the files and folder of SkyDrive in LoginCompleted event.

C#
Edit|Remove
private void btnSignIn_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
       {
           // If the user is signed in.
           if (e.Status == LiveConnectSessionStatus.Connected)
           {
               session = e.Session;
               client = new LiveConnectClient(e.Session);
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Accessing SkyDrive...");


               // Get the folders in their skydrive.
               client.GetCompleted +=
                   new EventHandler<LiveOperationCompletedEventArgs>(btnSignin_GetCompleted);
               client.GetAsync("me/skydrive/files?filter=folders,albums");
           }
           else  // Otherwise the user isn't signed in.
           {
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Not signed in.");
               client = null;
           }
       }


       /// <summary>
       /// Event for if the user just logged in.
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       void btnSignin_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
       {
           if (e.Error == null)
           {
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Loading folder...");


               // Check all the folders in user's skydrive.
               Dictionary<string, object> folderData = (Dictionary<string, object>)e.Result;
               List<object> folders = (List<object>)folderData["data"];


               // Loop all folders to check if the isolatedstoragefolder exists.
               foreach (object item in folders)
               {
                   Dictionary<string, object> folder = (Dictionary<string, object>)item;
                   if (folder["name"].ToString() == strSkyDriveFolderName)
                       strSkyDriveFolderID = folder["id"].ToString();
               }


               // If the IsolatedStorageFolder does not exist, create it.
               if (strSkyDriveFolderID == string.Empty)
               {
                   Dictionary<string, object> skyDriveFolderData = new Dictionary<string, object>();
                   skyDriveFolderData.Add("name", strSkyDriveFolderName);
                   client.PostCompleted += new EventHandler<LiveOperationCompletedEventArgs>(CreateFolder_Completed);
                   // To create the IsolatedStorageFolder in Skydrive.
                   client.PostAsync("me/skydrive", skyDriveFolderData);


                   // Write message to the UI thread.
                   UpdateUIThread(tbDebug, "Creating folder...");
               }
               else  // Check if the backup file is in the IsolatedStorageFile
               {
                   // Write message to the UI thread.
                   UpdateUIThread(tbDebug, "Ready to backup.");
                   UpdateUIThread(tbDate, "Checking for previous backups...");
                   btnBackup.IsEnabled = true;


                   // Get the files' ID if they exists.
                   client = new LiveConnectClient(session);
                   client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(getFiles_GetCompleted);
                   // Get the file in the folder.
                   client.GetAsync(strSkyDriveFolderID + "/files");
               }
           }
           else
           {
               MessageBox.Show(e.Error.Message);
           }
       }

 

Step 9:               Before download and upload, we must check whether the backup file exists in the folder.

C#
Edit|Remove
/// <summary>
       /// Check whether the backup file exists in the folder.
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       void getFiles_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
       {
           List<object> data = (List<object>)e.Result["data"];


           // Write message to the UI thread.
           UpdateUIThread(tbDate, " Getting previous backup...");
           DateTimeOffset date = DateTimeOffset.MinValue;


           foreach (IDictionary<string, object> content in data)
           {
               if (((string)content["name"]).Equals(fileName))
               {
                   fileID = (string)content["id"];
                   try
                   {
                       date = DateTimeOffset.Parse(((string)content["updated_time"]).Substring(0, 19));
                   }
                   catch (Exception ex)
                   {
                       // Write message to the UI thread.
                       UpdateUIThread(tbDebug, ex.Message);
                   }


                   break;
               }
           }


           if (fileID != null)
           {
               try
               {
                   string strTemp =
                       (date != DateTimeOffset.MinValue) ? "Last backup on " + date.Add(date.Offset).DateTime : "Last backup on: unknown";


                   UpdateUIThread(tbDate, strTemp);
               }
               catch (Exception ex)
               {
                   // Write message to the UI thread.
                   UpdateUIThread(tbDebug, ex.Message);
                   UpdateUIThread(tbDate, "Last backup on: unknown");
               }
           }
           else
           {
               UpdateUIThread(tbDate, "No previous backup available");
           }
       }

 

Step 10:            Finally, to achieve the important features of this sample: backup. We will use a button to launch the UploadFile method. In UploadFile method, we first obtain Isolated storage's files need to be backed up. Then go to the SkyDrive to check if the corresponding folder and file exists. Finally, asynchronous upload files.

C#
Edit|Remove
private void btnBackup_Click(object sender, RoutedEventArgs e)
       {
           if (client == null || client.Session == null)
           {
               MessageBox.Show("You must sign in first.");
           }
           else
           {
               if (MessageBox.Show("Are you sure you want to backup? This will overwrite your old backup file!", "Backup?", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
               {
                   UploadFile();
               }
           }
       }


       /// <summary>
       /// The IsolatedStorageData folder have been created.
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void CreateFolder_Completed(object sender, LiveOperationCompletedEventArgs e)
       {
           if (e.Error == null)
           {
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Ready to backup.");
               UpdateUIThread(tbDate, "No previous backup available.");


               Dictionary<string, object> folder = (Dictionary<string, object>)e.Result;
               // Get the folder ID.
               strSkyDriveFolderID = folder["id"].ToString();
               btnBackup.IsEnabled = true;
           }
           else
           {
               MessageBox.Show(e.Error.Message);
           }
       }


       /// <summary>
       /// Upload Files.
       /// </summary>
       public void UploadFile()
       {
           // The folder must exist, it should have already been created.
           if (strSkyDriveFolderID != string.Empty)
           {
               this.client.UploadCompleted
                   += new EventHandler<LiveOperationCompletedEventArgs>(IsFile_UploadCompleted);


               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Uploading backup...");
               UpdateUIThread(tbDate, "");


               try
               {
                   using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
                   {
                       // Upload many files.
                       foreach (string itemName in iso.GetFileNames())
                       {
                           fileName = itemName;
                           readStream = iso.OpenFile(fileName, FileMode.Open, FileAccess.Read);
                           client.UploadAsync(strSkyDriveFolderID, fileName, readStream, OverwriteOption.Overwrite, null);
                       }


                       // [-or-]


                       // Upload one file.
                       //readStream = iso.OpenFile(fileName, FileMode.Open, FileAccess.Read);
                       //client.UploadAsync(strSkyDriveFolderID, fileName, readStream, OverwriteOption.Overwrite, null);
                   }
               }
               catch (Exception ex)
               {
                   MessageBox.Show("Error accessing IsolatedStorage. Please close the app and re-open it, and then try backing up again!", "Backup Failed", MessageBoxButton.OK);


                   // Write message to the UI thread.
                   UpdateUIThread(tbDebug, ex.Message + ".Close the app and start again.");
                   UpdateUIThread(tbDate, "");
               }
           }
       }


       /// <summary>
       /// Check if the backup have finished.
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="args"></param>
       private void IsFile_UploadCompleted(object sender, LiveOperationCompletedEventArgs args)
       {
           if (args.Error == null)
           {
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Backup complete.");
               // In order to prevent the crash when user click the backup button again, dispose the readStream.
               readStream.Dispose();
               // Write message to the UI thread.
               UpdateUIThread(tbDate, "Checking for new backup...");


               // Get the newly created fileID's (it will update the time too, and enable restoring).
               client = new LiveConnectClient(session);
               client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(getFiles_GetCompleted);
               client.GetAsync(strSkyDriveFolderID + "/files");
           }
           else
           {
               // Write message to the UI thread.
               UpdateUIThread(tbDebug, "Error uploading file: " + args.Error.ToString());
           }
       }

 

Step 11:            Build the application and you can debug it.

More Information

Working with Microsoft SkyDrive folders and files (Live Connect)
http://msdn.microsoft.com/en-us/library/live/hh826531
Dispatcher.BeginInvoke Method (Action)
http://msdn.microsoft.com/en-us/library/cc190259%28v=VS.95%29.aspx
LiveConnectClient uploadAsync(String, String, File, LiveUploadOperationListener) (Live Connect)
http://msdn.microsoft.com/en-us/library/live/hh913602.aspx