Published: 02 Sep 2010
By: Manfred Pohler
Download Sample Code

This article shows how to use the Facebook graph_api (http://developers.facebook.com/docs/api) in a windows phone 7 (wp7) Silverlight application. All used tools are free software – for downloads take – take a look at the links at the end of this document.

Contents [hide]

The wFace – windows phone 7 facebook integration Series

This article series shows how to use the Facebook graph_API (http://developers.facebook.com/docs/API) in a windows phone 7 (wp7) Silverlight application. All used tools are free software - for downloads take a look at the links at the end of this document.

  • Part1
  • Part2
  • Part3
  • What we’ve done so far

    We made a windows phone 7 application with 2 forms. A MainForm with some buttons and login page. This login page provides us with an access_token which we need to make Facebook API calls.

    Our MainForm looks like this:

    Figure 1: Application Main page

    Application Main page

    And in code behind we have the following handlers:

    Important Update to Part 1

    In part one I described how to retrieve the access token (bug workaround). I did miss the "expires" parameter in the code. This parameter is optional - but we can get it in the results so we have to get rid of it.

    This is the code to handle it:

    Retrieving data

    Our next step is to retrieve data from Facebook. The page loaded handler already enables the buttons when we are logged in, so we can focus on handling the button events.

    Let's start with the LoadUserData button.

    In the Facebook graph_API documentation (http://developers.facebook.com/docs/API) we learn that:

    • All responses are JSON objects. We'll discuss this later.
    • All objects can be accessed in the same way
    • Objects are connected via relationships
    • There is a special object named "me"

    Let's take a closer look at point 2. The examples show links like https://graph.facebook.com/btaylor or https://graph.facebook.com/25190... This means we have to provide a name or an ID to access objects.

    And for point 3 we have links like https://graph.facebook.com/btaylor/friends. In simple words: these "relationships" are something like the basic object link followed by a "subdirectory" which provides the subject we want to access.

    Last not least (for point 4) the name (ID) of the object (as in point 2) can be replaced with the special name "me". In this case we get access to logged in account. This will mostly be our favorite object, since the user gave us (our Facebook application) access to his elements.

    Finally point 1 tells us that we will get all data as "JSON objects". JSON is a common format specification to transfer (store) objects. WCF services are also capable to communicate using JSON formatted data. The good old ASP.NET Webservices used SOAP, an XML based format which produces (in most situations) dramatically more "noise". So the overhead is much bigger than with JSON.

    There are also other formats like BSON or simply binary transfer - but that is a different story.

    Let's focus on JSON. And the best way to do this is best done by looking on what's going on.

    Retrieving JSON with a browser

    If we open the link https://graph.facebook.com/btaylor in the Internet Explorer we get a message that the document type is unknown and are asked to store the result in a file.

    For Firefox an addon called JSONView https://addons.mozilla.org/en-US/firefox/addon/10869/ can be installed. This displays JSON results in the browser window.

    Calling https://graph.facebook.com/btaylor shows:

    Notice the gender property - it reads "männlich" which is a localized version of the gender name. Since I work on a German OS it shows the German name "männlich" (male). This is OK when we plan to display this information to our users - but to check the result in our software it would be better to get a predictable result.

    Retrieve "non localized" results

    Of course the results are always localized. But we decide the language and therefore get consistent results.

    To do this add the parameter locale=... to the URLs

    When we call https://graph.facebook.com/btaylor? locale=en_US we get:

    So now we have "male" and can easily compare in our software.

    By the way - do you remember the access_token? It seems as if the calls do even work without this "magic value". And definitely a lot of the calls do work. BUT - what we get is the "public data". If we add a valid access_token to the calls we'll get what we want (or to be serious - what our Facebook application was asking for). We can check this by trying to retrieve btaylor's friends list https://graph.facebook.com/btaylor/friends

    That's the (expected) result of such a call. For calls which are allowed in general (like access to btaylor's profile) we get no error message; instead we get limited data.

    So to get better results we need an access_token.

    Filtering results

    The Facebook graph_API provides ways to reduce the transferred data fields. Since transfer (last not least) costs money we should always use that "filtering" to reduce the amount of data transferred over the network.

    This is also describe in the developer documentation:

    To get what we want (our user data in this case) we will use a filtered query like this: https://graph.facebook.com/me?fields=id,name,gender,link,hometown,picture&locale=en_US

    This brings us back to our wp7 application.

    Extend our FBUri class

    Since we already have a nice class which provides methods to get our formatted URIs (inclusive parameters) we will extend this class with a URI that will give us our profile data.

    After adding a new URL and a method to get the URI including our access_token we can focus on data retrieval.

    How to get data programmatically

    There are different ways to get the data. In the first part of this article series we used a WebBrowser control. This was mandatory since we must provide a form where the user can enter his credentials. And the idea behind this (maybe you remember) was - the user enters his credentials at a Facebook page - we (our software) never see his username / password.

    In the current case the things are different. First we get (as you see when you open such a link in IE) the data in a "not browser suitable" way. And second - there is no need to display something (like a form or so).

    The easiest way to make such web calls is little class called "WebClient". We know that the result of our calls will be a string which is JSON formatted. And using intellisense we find that the WebClient offers a method DownloadString which takes a URI as parameter.

    Your intellisense doesn't show DownloadString? That's correct! Since we work in Silverlight there are no synchronous web calls. What we have to use is DownloadStringAsync.

    For those of you not familiar with Silverlight Web calls

    Every web call in Silverlight is asynchronous. So the pattern is to set up a handler for "...Completed" and then call the ....Async method.

    In the handler you will either get an Error or a "Result" which is exactly the same you would get with a synchronous call of the method.

    Replace the btnGetUserData_Click handler in MainPage.xaml.cs with the following code:

    Let's take a look at this code. First we define a WebClient. In our button handler we check if this thing is null. If so, we create it and attach a completed handler.

    Next we try to call DownloadStringAsync. We use a try / catch here since such calls can fail without ever reaching the completed handler. A typical example is if you provide a wrong formatted URI.If the call is accepted further errors (like host not reachable or error results from the called site) will be handled in the completed handler.

    The completed handler (for the moment) simply checks for errors. If no error occurs we'll display the result in our UI (the blue text at the end of the form) and (if you debug the application) in the VS output window.

    This is what a result might look like:

    Here another result:

    Exactly what we've been asking for. Notice that the second result contains "hometown" which is also an object inside the "outer object" (curly brackets surround objects). The reason for this difference - Nina did not fill "hometown" in her user profile, while I did. So always expect the absence of values / properties in Facebook results.

    Further this is a simple string - what we need in our .NET world is a class. Since the JSON structure is pretty easy we could write a parser but the good news we will get one for free.

    You remember, before I mentioned that WCF also supports JSON data. And (I didn't mention but treat it as fact) Silverlight has building WCF support. So there must be some kind of Serializer which can handle JSON data.

    JSON Serialization

    Sherlock:It is there Dr. Watson let's use it

    Watson:How can we find it Mr. Holmes?

    Sherlock:We know it is a Serialzer...

    Watson:already search System.Runtime.Serialization - I could not find it Mr. Holmes!

    Sherlock:We know it has some relation to Web Services - did you check System.Servicmodel.Web?

    Watson:Just a moment - I added a reference, but I find nothing in System.Servicemodel.Web!

    Sherlock:It is a Serializer - try System.Runtime.Serialization...

    Let's follow Dr. Watson and add a reference to System.Servicemodel.Web to our project. Next place your cursor somewhere in the completed handler and type System.Runtime.Serialization. Intellisense should pop up and in the List you should find Json. Select it and next you should get a class called System.Runtime.Serialization.Json.DataContractJsonSerializer.

    This is the class we have been searching for. But what does "DataContract" mean? If you work with WCF you will learn that there are a lot of contracts. And a DataContract is simply a contract which defines how data "looks" (it's a bit more but we don't care here) - or for our need how it should be serialized.

    Namespaces in different assemblies

    It is normal to extend (provide) some functionality in "related" assemblies.

    In the Serialization case we have System.Runtime.Serialization which is extend by Json.

    Since Json is (primarily) used in Web Services the System.Runtime.Serialization namespace is extended in the System.Servicemodel.Web assembly.

    To define / use Data contracts we also need a reference to the System.Runtime.Serialization assembly. So add a reference to the project.

    As mentioned above we want to have the user data in a class. We already have a folder HelperClasse - add a new class to it - FBUser. Next we will analyze the data we WANT to get from Facebook and build properties for in our class. You remember, Name, Link, Picuture, Gender and Hometown are the elements what we are looking for. And for further calls to the API the ID would also be good to have.

    But before we do this let's take a look at the data we got from our Facebook API call.

    Notice two things - the ID of our user is surrounded by quotation marks while the field id in hometown is not! In our case this doesn't matter - but for other calls this may be relevant. "values" are strings while values without quotation marks are numbers. So let's build the properties - but doing this we will change the names to get a "good looking notation".

    Notice 2 things. First (for the sake of "simple code") I built a contained class named "FBHomeTown". Next I made the properties "null proof". You remember that the Facebook API doesn't return anything if a property is not set in the user account. This means that we always have to check if a value is present or not. Assume we want to check if the Hometown name is "Linz". With this "null proof" approach we can simply write:

    Else we would first have to check if HomeTown is null, further we must check in Name is null and so on.

    Now that we have our class the serializer must be able to assign values to it. Of course it has no chance to find the members since we gave them different names. But this is where the contract takes place.

    We can add contract attributes to our class. They inform the serializer about the relations between our class and the data (JSON). Finally our class looks like this;

    Notice that the contained class FBHomeTown also has a DataContract attribute. Every property has its special DataMember attribute with a Name= parameter. There we fill the names we found in our JSON data.

    We are almost done with JSON - the only thing left is de-serialization. Using intellisense we learn that a DataContractJsonSerializer has a method Read which takes a stream as parameter. We (unfortunately) have a string with JSON data. To handle this we will build our own JsonStringSerializer. Add a class to our "HelperClasses" directory and name it JsonStringSerializer. To provide more flexibility we will add a generic method which returns a de-serialized class. As parameter we pass the strings we get from our Facebook API calls. The method looks like this:

    This method creates (depending on the generic type) a DataContractJsonSerializer. Next it uses the string to create a memory stream which will be passed to the ReadObject method. Notice that we use Encoding.UTF8 to get the bytes of our string. If your "JSON service" uses a different encoding you would have to change this.The Facebook API sends data UTF8 encoded - so we use it here.

    Let's stick the things together. In the first part of this series we already built our MainPage UI. The interesting part (for now) is the Grid named fbUserGrid:

    First we have a "headline" - User Date. Then we have an image control which is bound to "PictureLink". "PictureLink" sounds familiar, doesn't it? YES - it is the name of one of our FBUser class properties. The same we have for Name, Gender and HomeTown.Name. For the last binding: it is possible to bind (as the name tells) a path not only to a property. So here we bind to the HomeTown property of our FBUser and in this class to the member Name.

    To bring in our FBUser instance we simply bind it to the grid. And the controls will then bind to the elements of the object which is bound to the grid.

    Let us change our completed handler. Be aware that binding could fail, so we try / catch this also.

    Notice that the FBUser member is defined static! Do you know why I did this?

    I mentioned in part one that the navigation framework creates / destroys pages when we navigate. In this case if we (for an example) navigate to the "Friends list" our MainPage is destroyed. When we navigate back we get a brand new MainPage - unfortunately without our FBUser.

    Navigation - YES we also have to handle this - bring back our FBUser to Grid binding. Change the Loaded event handler to:

    The last line binds our FBUser to the grid. If it is null (we didn't load it) simply no data is displayed.

    Time to run our project! Login, click "Load User Data" and you should see something like this:

    Figure 2: MainPage with user data

    MainPage with user data

    Looks good, doesn't it?

    If you answer the question with NO - right click on your project in the VS Solution Explorer and choose "Open in Expression Blend..." - make your design changes there.

    Retrieving (more) complex data

    Since we have done our first simple data retrieval let us expand this a bit by loading a list of our friends.

    Before we go into details add a new URI to our FBUris class. Add the following lines:

    Next add a new "Windows Phone Portrait Page" to the project. Name it PGFriends. To open the page change the button handler in MainPage.xaml.cs to:

    By the way - you can try to change the "static FBUser" to non static and run the application. You'll see that after you open PGFriends and come back to MainPage that the user data is lost.

    Retrieve the friends list

    Above we have seen that the Facebook API provides "relations". This is exactly what we need in this case. And we also have seen that a call to the "friends relation" needs an access_token. We already have a function for this in our FBUri class and further we know that a WebClient is what we need to make an API call. And since our page shall provide us with a friends list the only thing it should do is to obtain the list and show it. So there is no need for buttons or whatever. The page loads - we get the list and display it - done. This and the knowledge we have from retrieving our user data we can simply add the needed code to our PGFriends.

    Add a loaded handler simplified

    Double click somewhere in the blank space of the form in the "Page Designer".

    This will add a PageLoaded handler.

    First add a "Loaded" event handler than write (copy) the following code:

    This looks pretty the same like the code we use to load our user data. But since we don't know what we will get and how to display it we simply write the results to the VS output window (for the moment).

    Let's run the application and see what we get. It is a good idea to place a breakpoint at the line where we get the result, so we can inspect the data there. What we get is something like this:

    This is our friend list. All data here is public - except the fact that they are a friend of mine. In other words, what I get is a part of the public data. The access_token is needed to get the list. So what we get is no "secret" at all. The only protected thing is the list itself. Anyhow I've hidden some of the data (ID's and Name) except for my relatives. Notice a thing about the name there is a "name": "xxx Pfl\u00fcgl", this is encoded and will extend to an umlaut.

    We get a "something" containing FBUser objects. Of course the object do only contain two elements this should not irritate us - we know Facebook result can have "missing properties".

    More interesting is how we get the list. If we "read" JSON it says we get:

    • An object with a data property
    • The data property is something enclosed in square brackets []
    • In the brackets we find FBUser objects

    This is how JSON represents Arrays. So to de-serialize our data we need a class that has a property "data" which is a FBUser object array.

    OK, let us add a new class in HelperClasses and name it FBFriends (notice the plural):

    I tend to say building this class was not really a hard job.

    Display the friends list

    Now let's display our friends in a nice list. I imagine a list with the user image (profile picture) and the name in a second column. The problem - we only got Name and ID in our list. So the "PictureLink" of our FBUser object is empty.

    Luckily Facebook provides separate link to access profile pictures. All you need to know is the ID of the user.

    The link is: http://graph.facebook.com/ID/picture So let us extend our FBUser class with a property for this.

    Notice this property is read only and needs no DataMember attribute since it is not serialized.

    There is another thing we know - Facebook profile pictures have a dimension of 57x57 pixels. Knowing this we can easily create a ListBox with "good looking" entries. Open PGFriends and add the following markup to the ContentGrid:

    Again I added the well known info section at the bottom of the page. For the ListBox I provided a template which is a grid with a line height of 80 (to get margins) and in the first column an Image with the Height 60. This is bound to the new FBUser Property "PicLink".

    Further notice that I bound the ItemsSource to the path "Friends" (which is the array in our FBFriends class). So we simply have to set the Listbox's DataContext to an object of the type FBFriends.

    The final code also changes the Debug.WriteLine to a more useful display in the two information lines on the bottom of our page.

    Of course we could cache our friends or do other optimizations. But to simply obtain and display the list this is all we need to do. And here is a part of the result:

    Figure 3: A part of the Friends List

    A part of the Friends List

    Notice here that the "name": "xxx Pfl\u00fcgl", was translated to an Umlaut. And also notice that my daughter didn't correctly rotate her profile picture.

    Sending data

    The final thing is to post to our wall. To do this we should know that:

    • A post (feed entry) has some "special sections"
    • The data must be "posted"
    • The result is the id of the new post

    I'll not explain the sections of a wall post in detail. You can find this in the Facebook API documentation. Or better learn it by analyzing a self made post.

    To post let us first create a new page. Add a new "Windows Phone Portrait Page" to the project. Name it PGPost. To open the page change the button handler in MainPage.xaml.cs to:

    And before I dive deeper in how to post to the wall let us build the UI for the PGPost page. Change the ContentGrid to:

    Please do not forget to add the button handler (just delete the text - type a blank and follow intellisense). Notice 2 things here:

    • We bind data to the controls
    • We use "Mode=TwoWay" in most cases

    And this is what the page should look using this markup:

    Figure 4: The Post Page

    The Post 

Page

    To enable easy data-binding we will create a class which represents a wall post. Add add new class to our HelperClasses directory and name it FBWallPost - change the code to:

    Here you can see the possible values of a wall post. These values have to be sent to the Facebook API. We have to do the same what Facebook does - if a property has no value - don't send it. The data must be sent in a format similar to the other parameters we passed till now. With one little difference - but that comes later.

    First let us write a function which returns such a "query string":

    Notice that:

    • The parameter access_token is not preceded with an ampersand or a question mark.
    • Every parameter (except the access_token which we never "decoded") is UrlEncoded
    • If a property is empty - we simply do not add it to the result string

    What we have to do now is to create such an object, bind it to our grid and when the user presses the send button we simply call this method to create our "well formatted" data we will send to Facebook.

    First we add a loaded event handler to our page and add the following code:

    We also added our well known UpdateUI function. Notice that I call the FBWallPost constructor with true - which produces sample data. So we don't have to fill the form by hand just to see how posting works.

    Of course our FBUris class needs to be extended with the "post to wall" method. Add the following lines there:

    Notice that we don't pass the access_token like we did in the prior methods. I wrote above that there is a difference between the former called functions and writing a post to the wall. Here it comes!

    While the data we sent before was very limited (in the meaning of amount / size), a wall post can be pretty large. This means it could exceed the "maximum URL length". So data must be passed in a different way. What we did till now was (from a HTTP perspective) a GET operation. GET operations transfer their data directly via the URL. The rule - after the address follows a question mark, followed by a list of name / values pairs separated with an ampersand.

    Above (describing the GetPostParameters method) I asked you to notice that access_token is not preceded with a question mark (or an ampersand). The reason is that that question mark is specific to the GET operation.

    In our case we will use a different operation - called POST. Here the data is transferred in the HTTP headers. This eliminates the "URL length limit". And it means that Address and data are no longer one "string". Instead we have the URI and the data as two parts of the call. That is why GetPostMessageUri only returns a native address and doesn't need the access_token. This is instead provided via the GetPostParameters method of our FBWallPost class.

    Data binding was set two "TwoWay mode" which means that what we type is transferred back to the bound object. So all we have to do is send what the object contains. Let's do this by changing the button event handler in our PGPost page:

    Notice that we now use a different method of the WebClient class. Instead of DownloadStringAsync we use UploadStringAsyn. Therefore (of course) we have to handle a different completed event.

    And notice further that UploadStringAsync has a second parameter where we provide the data transfer mode - POST in this case - and the data values are passed as third parameter.

    When we run the application and post to our wall we can check the results by visiting our Facebook home page. Let's run it and check (without changing any data in the form) the results:

    Figure 5: Facebook post made with our wp7 application

    Facebook post made with our wp7 application

    Notice the little rectangle in front of "about a minute ago..." This can be replaced with an icon. You can change this in the application settings at http://www.facebook.com/developers/

    Further the image as well as "Testname" are linked to the link you provide with your post. And last not least the text "NinasFirstApp" is linked to the "application page". It is something like a normal Facebook page. You can customize this page to provide further information about your application.

    This is the end

    So finally we reached the end of our series. There are much more operations available in the Facebook API. But they are all very similar to what we have done here. Check the "call URL", provide a test call and analyze the results. Write your classes for the results - implement the JSON data contract - done.

    What is left?

    In general this example contains most of the things you need to know if you want to write a wp7 application that interacts with the Facebook API. But there are some pitfalls in the API. You will stumble into one of them almost for sure (if you do more than what we have done here). But hopefully other developers had the same problem and there is already a solution on the web. One (very famous) pitfall is the "logout".

    I only must enter my credentials once

    You may have notice that after the first run of your application the login page simply loads some pages and tells that it is logged in.

    Restart the simulator - and you get asked for credentials again.

    Keep your app closed for several hours (>2) and you are also asked again.

    The reason for this - Facebook caches your credentials in cookies on the client and automatically redirects you if they access_token is still valid or if the user choose "remember me" at logon.

    There is a "logout page" - which finally doesn't work. In general it works - but only if you delete some "forgotten cookies".

    Wp7 provides no access to the cookies of your app - so this fails. But there is hope! Redirect the user to:

    string strLogoutURL2 = "http://m.facebook.com/logout.php?confirm=1&next=" + HttpUtility.UrlEncode ("http://www.facebook.com");

    wbLogin.Navigate(new Uri(strLogoutURL2, UriKind.Absolute));

    You will reach a page with the address http://touch.facebook.com/login.php From here close your "logout page" or navigate to the "Facebook API Login page" as we did before.

    There are plenty of other things left - good design, perfect error handling, a good pattern (MVVM, MVC, ...) for data / UI separation, animations, automatic navigation and so forth.

    Just start with the login page - there is already (commented) code which redirects the user back after he authenticate our Facebook application. A potential enhancement would be a in-between page which just displays some kind of "welcome my friend" which disappears after some time.Meanwhile you could fetch the user data (and / or) friends list in a background thread...

    Resources

    The wFace – windows phone 7 facebook integration Series

    This article series shows how to use the Facebook graph_API (http://developers.facebook.com/docs/API) in a windows phone 7 (wp7) Silverlight application. All used tools are free software - for downloads take a look at the links at the end of this document.

  • Part1
  • Part2
  • Part3
  • <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Manfred Pohler

    Sorry, no bio is available

    This author has published 5 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Android for .NET Developers - Location and Maps
    In Windows Phone and iOS getting the current position of the device in terms of latitude and longitu...
    Android for .NET Developers - Using Web Views
    In this article, I'll show a native app that contains a web-based view. The great news is that HTML ...
    Android for .NET Developers - Building a Twitter Client
    In this article, I'll discuss the features and capabilities required by an Android application to ta...
    Ref and Out (The Inside Story)
    Knowing the power of ref and out, a developer will certainly make full use of this feature of parame...
    Developing a Hello World Java Application and Deploying it in Windows Azure - Part II
    In this article we will see the steps involved in deploying the WAR created in the first part of thi...
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder Thanks for great tutorial Mike Connor 9/12/2010 1:29 PM
    The error is new within the last week George Cross 9/13/2010 12:32 AM
    placeholder Unable to post to wall Kaushik Dev 9/15/2010 1:00 PM
    Wall post Manfred Pohler 9/16/2010 5:54 AM
    placeholder Follow up: Wall post Manfred Pohler 9/16/2010 9:03 AM
    It works again Manfred Pohler 9/24/2010 6:18 AM
    placeholder RE: It works again Kaushik Dev 9/29/2010 1:28 AM
    RE: RE: It works again Kaushik Dev 9/29/2010 9:23 AM
    placeholder RE: RE: RE: It works again Manfred Pohler 9/29/2010 3:38 PM
    No changes at all Manfred Pohler 9/29/2010 6:49 AM
    placeholder Can we get wall data? Kaushik Dev 10/18/2010 3:20 AM
    RE: Can we get wall data? Manfred Pohler 11/22/2010 7:42 PM
    placeholder Thanks David Stanchi 11/22/2010 6:31 PM
    Logout Hello World 11/24/2010 7:30 PM
    placeholder RE: Logout Manfred Pohler 11/25/2010 12:36 PM
    Login Matt M 12/4/2010 12:22 AM
    placeholder RE: Login Manfred Pohler 12/4/2010 5:47 AM
    RE: Login Manfred Pohler 12/4/2010 5:57 AM
    placeholder Part 3 is out Manfred Pohler 12/13/2010 7:14 PM

    Please login to rate or to leave a comment.