Backup your Windows Phone Isolated Storage data to SkyDrive using Live Connect API
As a Windows Phone developer you know that you can store your application local data to Isolated Storage. Isolated Storage restricts all your I/O operations so other applications cannot access or corrupt your data, which provides very efficient security of app’s and user’s data. You can store WP7 local data to IsolatedStorageSettings, database or folders and files.
You also know that you have to backup your data in case of data loss or something else. Classic backup scenario includes simple data upload to your web application or cloud service. But if you tried to implement solution that includes upload to SkyDrive, DropBox or any other free cloud hosting service, you know that situation is not so simple, primarily because there are not any official API providers for Windows Phone platform. Off course, there are some community libraries that can help you, but in most cases they are not suitable for WP7 solutions or are very hard to implement. For example, there is community SkyDrive API library called SkyDrive .NET API Client, based on SkyDrive WebDAV web services, which works fine in web or desktop environment, but not for WP7. SkyDrive’s problem was lack of official Microsoft documentation and API. But few months ago Microsoft finally announced REST APIs for Windows Live platform. It was called “Messenger Connect”, but problem was that was primarily targeted to web client script developers, because APIs were exposed as JavaScript APIs. But no matter what, it was good sign. It was matter of time when we can expect managed (C#) API for Windows Live. On September 13th, Microsoft as a part of BUILD conference preliminary release of Windows 8, also published Live Connect, the new API that supports Metro style apps and Windows Phone apps. You can check out Live Connect now by visiting http://dev.live.com. Final release of Live Connect is expected in November 2011. You can download Live SDK Developer Preview from here.
Referencing the APIs with C#
When you download and unpack Live Connect SDK Developer Preview you will find Live Connect MSI setup file (LiveSDK.msi) and preliminary CHM documentation (LiveConnectPrelim.chm). When you install LiveSDK, you will find two new assemblies in Visual Studio .NET reference list: Microsoft.Live and Microsoft.Live.Controls:
Also, API ships with Live Connect Sign In control that will help you with user sign-in scenarios. If the control is not visible in your Toolbox you can register it by browsing Windows Phone\References\Microsoft.Live.Controls.dll assembly in Live SDK installation folder.
Getting a client ID and configuring your app
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 00000000603E0BFE:
Sign-in user
To enable user to upload data to SkyDrive (or use any other Windows Live service like Hotmail, Contacts, Messenger or settings), the user must be signed in to Live Connect. A standard way to do this is by adding sign-in functionality to your app. This functionality (typically a button or a hyperlink) enables a user to provide their Microsoft account credentials. After the Live Connect APIs verify these credentials, it returns an access token to your app. This access token confirms that the user successfully signed in, and it specifies which parts of the user’s info your app can work with and for how long.
Best way to prompt a user to sign in in your WP7 app is to use the Live Connect sign-in control. You do this by setting the sign-in control’s properties in XAML code as is shown in code above. You must declare following namespace in your XAML page:
<phone:PhoneApplicationPage
…xmlns:my="clr-namespace:Microsoft.Live.Controls;assembly=Microsoft.Live.Controls">
Also, you must set the Scopes, ClientId, RedirectUri and SessionChanged properties of Sign in control:
Scopes defines permissions from the user who owns the info to access his or her info or to create new objects on his or her behalf. In our scenario wl.skydrive_update scope is required to access and update user’s SkyDrive folders and files.
ClientId property is client ID of your Windows Live Application.
RedirectUri property defines landing page for you application. However, in Windows Phone scenarios that is not needed. In our case we will set RedirectUri in SignIn control to https://oauth.live.com/desktop.
SessionChanged property sets event handler method. Here is example how to set SessionChanged and LoginCompleted events in SignIn control that you put into your XAML page:
void btnSignin_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
{
if (e.Session != null &&
e.Session.Status == LiveConnectSessionStatus.Connected)
{
client = new LiveConnectClient(e.Session);
infoTextBlock.Text = "Signed in.";
client.GetCompleted +=
new EventHandler<LiveOperationCompletedEventArgs>(btnSignin_GetCompleted);
client.GetAsync("me", null);
}
else
{
infoTextBlock.Text = "Not signed in.";
client = null;
}
}void btnSignin_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
if (e.Error == null)
{
infoTextBlock.Text = "Hello, signed-in user!";
}
else
{
infoTextBlock.Text = "Error calling API: " +
e.Error.ToString();
}
}
For more information about user’s sign in, check “Signing users in” chapter in Live Connect documentation.
So, if you successfully set your XAML page and sign in code, following screenshots show user’s “sign in scenario”:
1) Click Sign in button:
2) User is redirected to Windows Live authentication page:
3) User is prompt to okay scopes that your application needs:
4) User is signed:
Upload data to SkyDrive
In this scenario I used Camera Capture feature of WP7 to capture camera image, save it to Isolated Storage and upload it to dedicated SkyDrive folder. CameraCaptureTask is used to capture desired image and save it to Isolated Storage. Following code describes capturing and image saving to Isolated Storage:
private LiveConnectClient client;
private CameraCaptureTask cameraCaptureTask;
private string cameraRollFileName = "MyCameraRollPicture.jpg";
private string skyDriveFolderName = "IsolatedStorageFolder";
private string skyDriveFolderID = string.Empty;private void Camera_Click(object sender, EventArgs e)
{
try
{
cameraCaptureTask.Show();
}
catch (System.InvalidOperationException ex)
{}
}private void cameraCaptureTask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
BitmapImage bmp = new BitmapImage();
Stream capturedImageStream = e.ChosenPhoto;
bmp.SetSource(capturedImageStream);
this.SaveImageToIS(bmp);
}
}private void SaveImageToIS(BitmapImage bitmapImage)
{Uri uri = new Uri(cameraRollFileName, UriKind.Relative);
string file = uri.ToString();
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(file))
store.DeleteFile(file);
IsolatedStorageFileStream fileStream = store.CreateFile(file);
StreamResourceInfo sri = null;
sri = Application.GetResourceStream(uri);
WriteableBitmap wb = new WriteableBitmap(bitmapImage);
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
}
When user captures photo and clicks upload button, following scenario is happening:
1) Get info about user’s SkyDrive folders:
private void UploadPhoto_Click(object sender, EventArgs e)
{
if (client == null || client.Session == null || client.Session.Status != LiveConnectSessionStatus.Connected)
{
MessageBox.Show("You must sign in first.");
}
else
{
client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(GetFolderProperties_Completed);
// If you put photo to folder it becomes album.
client.GetAsync("me/skydrive/files?filter=folders,albums");
}
}
GetAsync is a helper function for making calls to the REST API. In our case we will get data about all folders and albums in user’s SkyDrive root folder.
2) Process data returned by GetCompleted handler:
private void GetFolderProperties_Completed(object sender, LiveOperationCompletedEventArgs e)
{if (e.Error == null)
{
Dictionary<string, object> folderData = (Dictionary<string, object>)e.Result;
List<object> folders = (List<object>)folderData["data"];foreach (object item in folders)
{
Dictionary<string, object> folder = (Dictionary<string, object>)item;
if (folder["name"].ToString() == skyDriveFolderName)
skyDriveFolderID = folder["id"].ToString();
}if (skyDriveFolderID == string.Empty)
{
Dictionary<string, object> skyDriveFolderData = new Dictionary<string, object>();
skyDriveFolderData.Add("name", skyDriveFolderName);
client.PostCompleted += new EventHandler<LiveOperationCompletedEventArgs>(CreateFolder_Completed);
client.PostAsync("me/skydrive", skyDriveFolderData);
}
else
UploadFile();
}
else
{
MessageBox.Show(e.Error.Message);
}
}
REST will return “data” text value which holds information about SkyDrive root folder. Convert “data” information into collection of folders and iterate them to check if desired folder exists. In this case it is value of variable skyDriveFolderName.
private string skyDriveFolderName = "IsolatedStorageFolder";
If folder exists we will took its folderID value, because that value is needed to define upload folder in next steps. If folder does not exists, we have to create it using PostAsync method. When folder is created following method for handling CreateFolder_Completed event is executed and new folder ID value is assigned to skyDriveFolderID variable:
private void CreateFolder_Completed(object sender, LiveOperationCompletedEventArgs e)
{
if (e.Error == null)
{
infoTextBlock.Text = "Folder created.";
Dictionary<string, object> folder = (Dictionary<string, object>)e.Result;
skyDriveFolderID = folder["id"].ToString();
UploadFile();
}
else
{
MessageBox.Show(e.Error.Message);
}
}
3) Upload image to SkyDrive’s "IsolatedStorageFolder" folder:
When we are sure that desired folder exists in user’s SkyDrive, last step is uploading file from Isolated Storage.
private void UploadFile()
{
if (skyDriveFolderID != string.Empty)
{
string[] filePathSegments = cameraRollFileName.Split(‘\\’);
string fileName = filePathSegments[filePathSegments.Length - 1];
var scopes = new List<string>(1);
this.client.UploadCompleted
+= new EventHandler<LiveOperationCompletedEventArgs>(ISFile_UploadCompleted);IsolatedStorageFileStream fileStream = null;
try
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
fileStream = store.OpenFile(cameraRollFileName, FileMode.Open, FileAccess.Read);
}}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
this.client.UploadAsync(skyDriveFolderID, cameraRollFileName, true, fileStream, null);
}
}private void ISFile_UploadCompleted(object sender, LiveOperationCompletedEventArgs args)
{
if (args.Error == null)
{
Dictionary<string, object> file = (Dictionary<string, object>)args.Result;
// For some reason SkyDrive link property is not part of result.
this.infoTextBlock.Text = "File uploaded.";
}
else
{
this.infoTextBlock.Text =
"Error uploading file: " + args.Error.ToString();
}
}
And this is it.
User is notified that file is uploaded:
If you check you SkyDrive account, new folder with image will be there:
Complete working zip solution can be downloaded from here (don’t forget to put your app client ID in MainPage.xaml).
You can download Live SDK Developer Preview from here.
Hi,
Nice article, thank you.
I tried to run your solution on my WP7. I created client id and put it in the MainPage.xaml. When I press “Yes” on the allow access page, Visual Studio throws a web exception “Not Found” and I stay logged out.
On the “My apps” page, I tried to set the “Mobile client app” to Yes,but that did not change anything.
Any ideas? I’m running Mango build 7712.
Is it possible to upload WAV or MP3 file using Live Connect API?
Mp3 and wav are not supported file formats in Live Connect API (I don’t know why). However RAW format is supported. It is headerless waveform format like PCM, but if you add header data in it (like WAV header data) you can play it with any audio player.
I suppose you want to save your WP7 microphone audio recordings to SkyDrive. Solution is to save microphone buffer data, add WAV header information, save it in Isolated Storage as RAW file, and then upload it to SkyDrive. I will try to do that in next few days, so I will write about my findings here on blog.
You have to get to this link to get to the Connect page: http://go.microsoft.com/fwlink/?LinkId=226223
I am getting below error message, when i try to upload xml document. Any help on this is appreciated.
{“The requested operation could not be completed. The provided file type is not supported. Only photos, videos and document file types are supported.”}
XML format is currently not supported in Live Connect SkyDrive API (see CHM preliminary documentation, topic “SkyDrive core concepts”). Workaround is to change XML file type to TXT and upload TXT file instead of XML.
Also, I suggest you to post message regarding your problem to Live Connect forums: http://dev.live.com/forums
WAV format wasn’t also supported, but after few questions about that issue Live Connect development team added WAV to list of supporder formats few weeks ago.
Anyone can provide sample on how to read file data from skydrive subfolder (MyDocuments/Document1.txt) ? That makes my life easy.
Hi, Niko
I just wrote a simple app using Live SDK JavaScript API for navigating my SkyDrive file system. It works ok.
I saw you use ‘GetAsync(“me/skydrive/files?filter=folders,albums”);’ to get only folders and albums of items in your WP7, so I tried to use ‘WL.api({path: “me/skydrive/files?filter=folders,albums”}, callbackFn);’ in my codes, but it does not work.
Also, I got an error message “The provided value for the input parameter ‘filter’ is not valid. A comma separated list of the following values is expected: ‘folders’, ‘albums’, ‘photos’, ‘videos’, ‘audio’.”
But I am sure what I wrote is ‘folders’ and ‘albums’, or ‘folders,albums’.
Is there any differences between using C# API and JavaScript API in this place?
So I should write it in another way for using the filter parameter while coding with JavaScript?
Thank you!
I’ve found the solution by myself
I should write ‘path: “FolderID/files”, method: “GET”, body: {filter: “folders,albums”}’
thanks for the nice article anyway!
is there a download example?
Yes, here: https://skydrive.live.com/?cid=8C7AE147A45DB17C&id=8C7AE147A45DB17C%21109&sc=documents
hey nikovrdolj,
i see my expression wasn’t convey clearly. i meant if there is a how-to download a file from skydrive =D
i can’t determine the setting to GetAsync(string path, object userState) and i didn’t find any good documentation on that. have you any idea?
(i dont want to download an image, but a created folder with files in it).
hopefully you have an idea
Gonzo,
Use GetAsync() to read folder and file properites and then DownloadAsync() method for file download. Good example is on official LiveConnect site:
http://msdn.microsoft.com/hr-hr/windowslive/hh561740.aspx#downloading_files
Thanks a lot for this excellent article! I believe RedirectUri has been removed for WP. I am wondering if the user can be kept signed in as long as the app is active. It is a nuisance that one has to go through the sign-in process every time he accesses the page requiring Live Connect.
Appreciation to my father who told me regarding this web site, this weblog is in
fact awesome.
Cool article.
It helped me more then SkyDrive forum
I followed the code until section 3) User is prompt to okay scopes that your application needs. So After user prompt to login with live id and pass. Eventually I can’t log in completely. If I debug I can following information:-
In function
private void btnSignin_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
e.Error = {“The provided request must include a ‘client_secret’ input parameter, unless the app is configured as a mobile app. If you’re the client application developer and you’re creating a mobile app, you must configure it as one through the application management site at https://manage.dev.live.com/.”} System.Exception {Microsoft.Live.LiveAuthException}”
e.Session is inactive.
what is wrong with me. Please help me. Thanks in advnce
Good day! Do you know if they make any plugins to help with SEO?
I’m trying to get my blog to rank for some targeted keywords but I’m
not seeing very good results. If you know of any
please share. Thank you!
Thank you Niko. This was really helpful!
Great article.
Reblogged this on Juan Luis Mancilla E. info.Blogger.
I actually have a tendency to agree with every little thing that ended up being
composed in “Backup your Windows Phone Isolated Storage data to SkyDrive
using Live Connect API Niko Vrdoljak’s Blog”. Thanks a lot for all the facts.Thanks a lot,Frankie
I really Feel article, “Backup your Windows Phone Isolated Storage data to
SkyDrive using Live Connect API Niko Vrdoljak’s Blog” ended up being good! Ican’t agree together with u more!
At last appears like I actuallystumbled upon a website truly worth reading.
Thanks for the post, Jenny
Are you aware that your web site is coming up with errors in Opera?
I needed to open up IE to finish reading. No big deal,
but you might want to take a look at that. I’m positive it’s costing you a
number of visitors.
I am really pleased to glance at this weblog posts which includes plenty of useful facts, thanks for providing these kinds of statistics.
Hello to every one, the contents present at this web page are truly amazing for people experience, well,
keep up the good work fellows.
I like the helpful information you provide in your articles.
I’ll bookmark your blog and check again here frequently. I am quite certain I’ll learn plenty of new stuff right here!
Best of luck for the next!
I love what you guys tend to be up too. Such clever work and coverage!
Keep up the good works guys I’ve incorporated you guys to blogroll.
I am curious to find out what blog platform you’re utilizing? I’m
experiencing some small security issues with my latest website and I’d like to find something more secure. Do you have any recommendations?