Adding SkyDrive Upload Support to Your Windows Phone App

Multiple applications that are already in the Windows Phone Marketplace operate with a variety of content, such as pictures, text files and music. More often than not, that content is stored locally, in the application isolated storage, and although it is a good way to preserve that content, this method is bound to create some inconveniences in case the user decides to switch phones or do a complete device reset. To avoid this, developers can leverage the Microsoft Live SDK, specifically the SkyDrive API that is exposed through it.

To make my case more realistic, I am going to bring up my Windows Phone project – Beem (you can find the free version here and the donation build here). As I am expanding the functionality base for the Beem Plus client, I decided that I need to do something to allow users to back up the stream recordings that they have. Those are MP3 files stored internally, captured directly from the incoming radio stream.

The interesting part about these recordings is the fact that their length varies. One user might record a 10 second track, another one might have hours of online podcasts. Therefore, it would be logical to let them backup that data, in case something goes wrong. The Microsoft Live SDK comes with out-of-the box support for Windows Phone, so once you download and install the SDK, all you need to do is add a Microsoft.Live and Microsoft.Live.Controls assemblies to the project. Those should be already present in Visual Studio, in the Extensions section in the References dialog.

It is important to mention that before, it was not possible to upload MP3 files to SkyDrive from third-party applications. My workaround to that was simply adding a .wav at the end of the uploaded file name. An extension mismatch would not cause any problems during playback on a Windows machine, and if necessary, it can easily be swapped manually. Since then, the restriction has been lifted and SkyDrive supports MP3 uploads.

You will integrate the Microsoft Account authentication in your application by adding a SignInButton control, also specifying the scope of your integration with the user account. This is a built in measure that prevents applications from abusing the system by notifying the user about the actions the application will be able to perform on the account.

Basic Setup

SignInButton is added in the XAML layer, and a sample snippet would look like this:

<live:signinbutton x:name="btnSignIn" clientid="CLIENT_ID_HERE" scopes="wl.signin wl.basic wl.offline_access wl.skydrive wl.skydrive_update" branding="Skydrive" texttype="Connect" visibility="Collapsed"></live:signinbutton>

First things first, take a look at the declared scopes. The application will be able to sign the user in (wl.signin), access the basic profile information (wl.basic), access the user account when the user is not necessarily online, allowing me to preserve the login information so that there is no repetitive login once the app successfully performed the authentication (wl.offline_access), access the basic SkyDrive metadata (wl.skydrive) and update the file layout in the SkyDrive storage (wl.skydrive_update).

The ClientID identifies your application and can be obtained here. Branding and TextType determine the appearance of your button, allowing you to customize the displayed logo and caption.

When the user clicks on the button for the first time, he will be prompted with a web authentication page, where he will be asked to enter his Microsoft Account credentials. Once the account passes the verification, the user will be prompted with another web page, that shows the permissions the application requests. It is important that you declare only the necessary permissions when declaring the scopes.

Once Yes is clicked in the dialog, the session information will be automatically stored in the application if necessary, so you don’t have to worry about manually preserving those. Every time the authentication engine is invoked, the SessionChanged event handler is invoked, so make sure you hook it to the button:

btnSignIn.SessionChanged += App.MicrosoftAccount_SessionChanged;

As a result, you can potentially obtain a LiveConnectSession, that will be consequently used to perform any request on the Microsoft service endpoints. However, you also need to make sure that that account was actually successfully connected, since the user can block the application.

public static void MicrosoftAccount_SessionChanged(object sender, Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs e)
{
if (e.Status == Microsoft.Live.LiveConnectSessionStatus.Connected)
{
MicrosoftAccountClient = new LiveConnectClient(e.Session);
MicrosoftAccountSession = e.Session;
MicrosoftAccountClient.GetCompleted += client_GetCompleted;
MicrosoftAccountClient.GetAsync("me", null);
}
else
{
Binder.Instance.MicrosoftAccountImage = "/Images/stock_user.png";
Binder.Instance.MicrosoftAccountName = "no Microsoft Account connected";
MicrosoftAccountClient = null;
}
}

The call to me/picture will return the URL for the profile picture for the currently authenticated user. Notice that I am getting the results by referencing the key names. When the raw JSON data is returned on a call, a dictionary is automatically created that contains the key-value pairs, that makes it easier to get the data without having to re-parse the data. The RawResult property still exposes the raw JSON.

Uploading the File

Once a file is already present in the isolated storage and the Microsoft Account is connected to the application, it is extremely easy to initiate the uploading process. Before doing that, however, you need to consider that every user has limited SkyDrive quota. The default amount of allocated storage for current users is 7GB, so make sure that you check whether there is any available space for the file that you are about to send. To do this, you need to perform a call to me/skydrive/quota.

client = new Microsoft.Live.LiveConnectClient(App.MicrosoftAccountSession);
client.GetCompleted += client_GetCompleted;
client.GetAsync("me/skydrive/quota", null);

This call will return two values – total quota and available space. Before the upload, compare the byte size of the file and the available space.

if (e.Result.ContainsKey("available"))
{
    Int64 available = Convert.ToInt64(e.Result["available"]);
    byte[] data = RecordManager.GetRecordByteArray(Binder.Instance.CurrentlyUploading);

    if (available >= data.Length)
    {
        MemoryStream stream = new MemoryStream(data);

        client = new LiveConnectClient(App.MicrosoftAccountSession);
        client.UploadCompleted += MicrosoftAccountClient_UploadCompleted;
        client.UploadProgressChanged += MicrosoftAccountClient_UploadProgressChanged;
        client.UploadAsync("me/skydrive", Binder.Instance.CurrentlyUploading,
            stream, OverwriteOption.Overwrite);
        grdUpload.Visibility = System.Windows.Visibility.Visible;
        ApplicationBar.IsVisible = false;
    }
    else
    {
        MessageBox.Show(@"Looks like you don't have enough space on your SkyDrive.
Go to http://skydrive.com and either purchase more space or clean up the existing storage.", "Upload",
            MessageBoxButton.OK);
    }
}

If there is available space, simply create a new instance of LiveConnectClient, with the current LiveConnectSession (you can keep it in the App class for global access) and use UploadAsync to pass the internal path to the file, the file name, the file stream and the overwrite method. By default, all files are being overwritten. Remember, however, that when you are specifying the path to the folder you want to upload the file to, you cannot use the normal path format, but rather refer to folders by their ID. You can find more details about it in one of my previous articles. For some folders, however, you can directly specify the path. Example: me/skydrive/my_documents.

UploadCompleted and UploadProgressChanged can be used to define application behavior during and after the upload, such as displaying a popup that shows the current upload percentage.

Making The Account Accessible App-Wide

One interesting fact worth mentioning in case you declared wl.offline_access as a pre-determined scope. The default behavior for the application is to authenticate the Microsoft Account when the page with a valid SignInButton is hit. My intent for Beem was to keep the SignInButton in the application settings, where it is expected by the end-user. However, in this case the user will only be automatically authenticated when the Settings page would be opened, which is something that does not happen too often, in contrast with the multitude of other pages that are being used internally.

The workaround to this small issue is really simple – make sure that you add a SignInButton with exactly the same scopes and ClientID in the main application page, and set its Visibility property to Collapsed. You will need to wire it up to the SessionChanged event handler, that can be the same for both sign-in buttons used in the application.

Trick or Treat – URI Associations In Windows Phone 8 Outside Bing Vision

With the release of the new Windows Phone 8 SDK, the developers are now able to create URI associations, where their application can be launched from the context of another application. For example, I can register a den: URI scheme to pass specific information to my application from any other installed application or resource, such as an email or a text message. That way, my application is no longer a standalone entity and it can interact easily with other applications in the Windows Phone ecosystem.

There is one interesting aspect, however. Custom URI schemes are not recognized by Bing Vision, which might be a problem if you generated a QR code that should launch your application. You will be able to launch http:// URLs, but custom applications will remain in their separate frame, out of reach of the stock app.

Although this might seem like an issue, it can easily be mitigated by using standard HTML redirect. Since Bing Vision correctly handles URLs, and Internet Explorer on Windows Phone supports redirects, you have a couple of options, one of them suggested by Nikola Metulev.

Have the user navigate to a URL that will redirect to the custom URI schema. Create a HTML page, that has the following source:

                        

What will happen here is when the user will navigate to this page from a Windows Phone, he will get redirected to the custom URI that was specified as the redirect target. It is not possible to enter custom URLs that do not follow the HTTP format in the Internet Explorer address bar, but you can still rely on content links and redirects. Of course, you could also use a third-party URL shortening web service that supports custom URI schemas, such as is.gd. You can shorten an URL and have a QR code automatically generated. That URL can be something like den:awesome, and from it you will obtain a valid HTTP URL that will then trigger the application launch.

First Summer Working at Microsoft

This summer I got an awesome opportunity, thanks to Dan Fernandez, Jeff Sandquist and Clint Rutkas – I worked as a vendor/intern on the Channel9 Coding4Fun team. Now, if you are not aware of what Channel9 is about, then you are totally missing out on a portal dedicated to everything Microsoft (with a focus on dev tech), so check it out.

At this point, I am not going to go into detail about the project I was working on, but I would like to highlight some important points learned during this period. Obviously, this list is nowhere close to being complete – I tried to focus more on the social aspect of the job. It definitely was one-of-a-kind experience, in a one-of-a-kind team. What I wrote below is just a small part of everything amazing that I experienced in Building 40 and outside of it. The points might be useful for perspective students who consider interning at Microsoft.

Network. And once again – network. From the very first day in the office, I realized that one of the most important things to do is to get to know the people around you. There are so many interesting things they can tell and show you. That way I met such awesome Microsoft employees as Mark DeFalco, Josh Allen, Steven Salazar, Arthur Yasinski and Geoff Knutzen. Your adventure starts in the office, make the most out of it!

Learn outside your area. So you know people. Wouldn’t it be great to also learn more about the work they do? Ask them questions, be curious. Even if it their development stack is not closely related to yours, you can learn so much simply by talking about the work done on tools and services that you might already be using.

Events are you opportunity. If you get a chance to go to an event, such as TechEd, make sure that, once again, you talk to people. Ask them questions about their work there and how it affects what your team does. Usually, I found out that the work developers and organizers do is much more complicated than what it seems from the outside, with points that I, as a developer, neglected to realize. Special thanks in this context go to Denise Begley and Jeannine Wisniewski – thanks to you I am now aware how event planning and logistics work on a much lower level. Also thanks to Larry Larsen and Golnaz Alibeigi for showing how video work becomes art during “peace” and “war” times.

Stuck looking at a piece of code? There is probably someone in the hallway that can help. While working on whatever I was working, I did hit roadblocks, and that’s where I could just go to Charles Torre or Mike Sampson to get a quick “here is how it might actually work” review. Brian Peek and Rick Barraza were also very helpful with their insights on the internal and external design. Forums come last, attempt to solve problems with in-person communication first.

Do go to after-work events with your team. There were often little “offlines” with Duncan Mackenzie and the rest of the team. It was a chance to see what’s going on outside work and what are some opportunities and places to discover around the Seattle area (when I had some free time, obviously). Same applies to team lunches. Spoiler alert: Mark, you get on this list too with Lucky Strike.

Discover Microsoft outside your building. That is, go and talk to people in other divisions, go to Microsoft events, visit the Microsoft gym and the surrounding areas.  Getting around on campus is fairly easy with the existing shuttle system. If not – you always have the option of a bus (public transportation is pretty well organized in the Seattle area).

Meet other interns. They will probably be in your apartment building, or in the next building on campus. Each of them has their own story on how they got to work at Microsoft and it’s always interesting to hear about their experiences and work.

Microsoft offers free coffee and soda/juices at work, so why not drink those? This is probably one of the most well-known perks, but regardless – it is a great addition to an already creative work environment. I wish I stacked all those coffee cups to see how much I drank. Maybe I need to write an app for that.

Do stuff outside Microsoft. Burning out might be your ultimate productivity killer, and if you are not pressed by a deadline, discover Seattle, the mountains and the lakes. Visit landmarks, take pictures, go kart racing and make/meet friends – there are plenty of opportunities in the area.

If the team makes fun (in good spirit) of what you do, you are probably doing good.

Bottom line: Microsoft builds a very social environment, take advantage of that. I love it.

Stay tuned and keep checking Channel9. Time for me to get back to college and work on more awesome things. Until next time!