Facebook Development with the .NET Compact Framework

4/7/2010

Peter Foot, In The Hand Ltd

November 2007

Summary

Facebook has become a huge phenomenon in social networking. The site exposes a developer API to support Web and desktop applications. In this article we will explore making use of this functionality from a smart device application. The source code to accompany this article demonstrates working with key aspects of the Facebook API and tightly integrating with Windows Mobile–specific APIs.

The Facebook Development Toolkit, including the Facebook.Compact library and related samples, are located on CodePlex, Microsoft’s Shared Source hosting site, at https://www.codeplex.com/FacebookToolkit.

Applies To

Microsoft Visual Studio 2005

Microsoft Windows Mobile 5.0

Microsoft Windows Mobile 6

Introduction

Facebook Development Toolkit

Supporting the Compact Framework

Register a Facebook Application

Store Your Keys

Root Certificates

Facebook Friends

Working with Events

Working with Photos

Conclusion

Introduction

Facebook is a social networking Web site that has grown immensely popular in recent times. Facebook exposes a rich developer API that allows you to build both Web applications, which integrate into the Facebook site, and stand-alone desktop applications, which can access Facebook content. This article will investigate the latter approach and how Facebook can be used from the .NET Compact Framework to build stand-alone smart device applications.

Facebook Development Toolkit

Facebook is an Internet service and exposes a Web service–based API. Instead of the Simple Object Access Protocol (SOAP) Web services that will be familiar to a lot of managed code developers already, Facebook uses a Representational State Transfer (REST) API. Because you cannot use Visual Studio to automatically create code to interact with this service you need to write the functionality to make requests and parse the responses. Fortunately, this has already been done for us in the form of the Facebook Development Toolkit. This is a desktop .NET library that exposes a simple object model. The project was created on behalf of Microsoft as a showcase starter kit for Visual Studio Express; in its current released form it doesn’t support the .NET Compact Framework. The project is hosted at CodePlex (www.codeplex.com), Microsoft’s shared-source hosting site. When I became interested in adding support for the Compact Framework to the toolkit I joined the CodePlex project and began to add modifications.

Supporting the Compact Framework

I created a separate project within the solution called Facebook.Compact. Into this I added all the existing code files as references to the existing code. This ensures that there is still only one set of source code so changes made in the desktop project will be reflected in the device version. I added a compilation constant of NETCF to the project; this allowed me to add in conditional compilation around pieces of code, which I needed to hide from the Compact Framework because they used functionality that is not available. For example, the desktop component uses a number of attributes that are not used in the Compact Framework at run time:

namespace Facebook.Components
{
#if !NETCF
    [ToolboxItem(true), ToolboxBitmap(typeof(FacebookService))]
    [Designer(typeof(FacebookServiceDesigner))]
#endif
    public partial class FacebookService : Component
    {

The design-time attributes are instead applied to the component using an .XMTA file. This improves the designer experience by hiding some properties that are not relevant at design time and adds some detail to others:

<?xml version="1.0" encoding="utf-16"?>
<Classes xmlns="https://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd">
  <Class Name="Facebook.Components.FacebookService">
    
    <Property Name="ApplicationKey">
      <Category>Facebook</Category>
      <Description>Access Key required to use the Api</Description>
    </Property>
    
    <Property Name="UserId">
      <Browsable>false</Browsable>
    </Property>

    <Property Name="Secret">
      <Category>Facebook</Category>
      <Description>Secret Word</Description>
    </Property>

    <Property Name="SessionKey">
      <Browsable>false</Browsable>
    </Property>

    <Property Name="SessionExpires">
      <Browsable>false</Browsable>
    </Property>

    <Property Name="LoginUrl">
      <Browsable>false</Browsable>
    </Property>

    <Property Name="LogOffUrl">
      <Browsable>false</Browsable>
    </Property>

    <Property Name="IsDesktopApplication">
      <Browsable>false</Browsable>
    </Property>
    
  </Class>
</Classes>

I also had to write some additional code to add in functionality that the desktop version was using. Primarily this was support for URL encoding strings. This is where special characters are replaced so that the string can be safely sent as part of a request URL or within a form post. The other addition was a basic implementation of WebClient.DownloadData which encapsulates using an HttpWebRequest to retrieve a response and return the raw bytes.

When writing a desktop (or in this case device) application, the only part of the interaction that cannot be done solely through the API is the initial authentication. This must be done through a Web page that is passed your application ID and presents a familiar login page to the user. For the .NET Compact Framework this is achieved through a dedicated form that hosts the WebBrowser control. This provides an integrated approach to login so we don’t have to perform the login in Microsoft Internet Explorer® Mobile and then switch back to our application. Unfortunately there isn’t a device specific version of the login screen so its appearance is less than ideal. Figure 1 below shows the login screen running on a Windows Mobile device.

Bb932386.b195e77d-886c-4d75-9f50-1812da195b31(en-us,MSDN.10).png

Figure 1. Facebook API Login page

Once the user has successfully authenticated the login form is automatically dismissed. We do this by checking the Url of the page the control navigates to. For applications that are not hosted on the Web, this will redirect to desktopapp.phpwhich informs the user to close the window and return to their application. The same login pages are used for both desktop and smart device applications. The code is in the Navigated event handler on the WebBrowser control:

private void wbFacebookLogin_Navigated(object sender,
      WebBrowserNavigatedEventArgs e)
{
      if (e.Url.PathAndQuery.IndexOf("desktopapp.php") > -1)
      {
         DialogResult = DialogResult.OK;
      }
}

All these modifications I made to the code are not present in the current installer package for the Facebook Developer Toolkit, so you will need to download the package in source form. This will give you the Solution and all source code for the library. You can download the latest code from:

https://www.codeplex.com/FacebookToolkit/SourceControl/ListDownloadableCommits.aspx

Unzip the .ZIP file to a folder within your My Documents folder. There is a folder called Device Samples in the solution, which contains the sample applications that we will refer to throughout this article.

Register a Facebook Application

Before you can create your own Facebook applications, you need to register to generate a unique API Key and secret phrase. The first step to this is to add the Developer application to your Facebook profile. Once you have added this application, go to the application page (https://www.facebook.com/developers/) and click the Set Up New Application button illustrated in Figure 2. You can then proceed to allocate a unique name for your application.

Bb932386.86b34aac-bae7-47e2-a8d3-005e0513c9f1(en-us,MSDN.10).png

Figure 2 Facebook Developer home page

The next page contains fields for all the configuration options for your new application. Figure 3 shows how this is filled in for an example application. You will need to go through this process to get an API Key that you can use with the following samples.

Bb932386.4390dea3-706b-43c8-9e72-54e2c202cac4(en-us,MSDN.10).png

Figure 3. New Application page

Once you have created an application, you can view your application ID and secret phrase from the My Applications page, which is accessible from the Developer application home page. Figure 4 shows the My Applications page. Your API Key and secret phrase will be shown in the blank area in the middle. You will need these to log in to Facebook from your application.

Bb932386.cdce00a9-b561-42f6-83e0-b1511956ec59(en-us,MSDN.10).png

Figure 4. My Applications page

You now have all you need to authenticate with Facebook from your application. As the API Key and secret phrase are required from the application, we’ll need to store it somehow on the device securely.

Store Your Keys

There are a number of ways you can store the API Key and Secret phrase values in your application. They are both strings containing hexadecimal data. The desktop samples store these values in a configuration file. For simplicity, in these sample applications we are writing the values to the registry on the device. You should not do this for a released product because they are visible in plain text to anyone with a registry editor. To use the following sample applications you’ll need to write the following registry values to the device. You can use the Remote Registry Editor tool that ships with Visual Studio.

HKEY_LOCAL_MACHINE\SOFTWARE\InTheHand\FacebookDeviceSample
ApplicationKey (String) = Your API Key
Secret (String) = Your Secret

All of the following sample applications will load the values from this registry location.

Root Certificates

Facebook authentication uses HTTPS communication for security; however, on Windows Mobile this causes a problem because the root certificate used by Facebook is not provisioned on the device by default. This means that secure HTTPS requests will fail. Luckily it is possible to work around this by downloading the root certificate and adding it to the device.

Information about the list of root certificates can be found at https://www.geotrust.com/resources/root_certificates/index.asp. This can seem rather daunting as the list is particularly long; you need to find the entry called “Root 5 - Equifax Secure Global eBusiness CA-1.” There you’ll find download links to save the .CER file. The certificate is available as both DER encoded and Base-64 encoded; if you are using Windows Mobile 5.0 make sure you pick the DER encoded version of this file. For Windows Mobile 6 you can use either version. https://www.geotrust.com/resources/root_certificates/certificates/Equifax_Secure_Global_eBusiness_CA-1_DER.cer

Right click and save the file to your computer, make sure you save the file with a .CER extension. Copy this file to your device, locate it using File Explorer on the device, and tap the file to install it. You can automate this process by including the .CER file with your deployment and launching it programmatically.

Facebook Friends

Now we have all the prerequisites for the samples, let’s dive right in with our first sample application. The first thing we think of when we consider a social networking site such as Facebook is the ability to maintain a list of contacts. The first sample we will look at will retrieve our friends list, and is called DeviceFriendsSample.

We have added a FacebookService component to the application form; this provides all the interaction with the Facebook API. The first task is to assign the API Key and secret phrase to the control and establish a connection to Facebook.

private void FacebookFriends_Load(object sender, EventArgs e)
{
      //connect to facebook
      facebookService1.ApplicationKey = 
            (string)Microsoft.Win32.Registry.GetValue(
       "HKEY_LOCAL_MACHINE\\Software\\InTheHand\\FacebookDeviceSample", 
            "ApplicationKey", "");
      facebookService1.Secret = 
            (string)Microsoft.Win32.Registry.GetValue(

      "HKEY_LOCAL_MACHINE\\Software\\InTheHand\\FacebookDeviceSample", 
            "Secret", "");

      facebookService1.ConnectToFacebook();

      RefreshFriendsList();
}

The RefreshFriendsList method performs the retrieval of the user’s friends and loads them into a ListView control. In order to reduce screen updates we call BeginUpdate and EndUpdate on the ListView control around the code to populate the list. As each User is read we populate the ListViewItem with the Name and assign the PictureSmall property, which is an Image, to the ImageList associated with the ListView control.

private void RefreshFriendsList()
{
      lvFriends.Items.Clear();
      ilFriends.Images.Clear();

      Cursor.Current = Cursors.WaitCursor;
      lvFriends.BeginUpdate();

      Collection<User> friends = facebookService1.GetFriends();

      int i = 0;

      foreach (User u in friends)
      {
            ListViewItem lvi = new ListViewItem(u.Name);
            lvi.Tag = u;
            lvi.ImageIndex = i;
            ilFriends.Images.Add(u.PictureSmall);
            i++;
            lvFriends.Items.Add(lvi);
      }

      lvFriends.EndUpdate();
      Cursor.Current = Cursors.Default;
}

Useful Web Pages

When using the Facebook API from the desktop or a web application there are a number of standard URLs that can take you to specific pages on Facebook. While this requires an active network connection, it offers the ability to see properties and perform operations that are not available through the Facebook API itself. There are mobile equivalents of each of these URLs that are better formatted for device use. The full list of mobile formatted URLs is in Table 1.

Table 1. Common Facebook Page URLs

URL Purpose

https://m.facebook.com/profile.php?id=xxxxx

Display a specific user profile.

https://m.facebook.com/event.php?eid=xxxxx

Display a specific event.

https://m.facebook.com/group.php?gid=xxxxx

Display a specific group.

https://m.facebook.com/poke.php?id=xxxxx

Poke the specific user.

https://m.facebook.com/message.php?id=xxxxx &subject=xxxxx&msg=xxxxx

Send the specified user a message.

https://m.facebook.com/photo_search.php?id=xxxxx

View all photos of a specific user.

https://m.facebook.com/wall.php?id=xxxxx

Read the user’s wall.

https://m.facebook.com/notes.php?id=xxxxx

Read the user’s posted notes.

In our friend’s sample, we make use of the first of these URLs. On the first Soft key we have a View menu item. When tapped this opens an Internet Explorer Mobile window open on the specific user. You could also use a WebBrowser control hosted within your application to remain more integrated. One limitation here is that use of the Web site requires a separate login, but it is possible for the user to save their login so that they are only prompted after a long period without use. Launching a specific URL requires a single call to Process.Start:

System.Diagnostics.Process.Start("https://m.facebook.com/profile.php?id=" 
      + u.UserId, "");

Figure 5 shows a contact profile in Internet Explorer Mobile.

Bb932386.af484fba-8121-4c0f-9235-0b509308343f(en-us,MSDN.10).png

Figure 5. Profile page

Synchronization

As we have already seen, some key pieces of user information are not exposed through the API for privacy reasons. However, it would be useful if we could synchronize the user images with Outlook Mobile so they can be used on the incoming call screen and on messaging forms. We can do that using the managed Pocket Outlook classes in the Microsoft.WindowsMobile.PocketOutlook namespace. On the menu of the DeviceFriendsSample application we have a Sync entry. When this is tapped we start enumerating through the friends and check for matching contacts in the users address book. When a contact is found with a matching first and last name we open that contact item for editing. If no matching contact is found we create a new Contact item. In order to assign an image to a Contact we must first save the image to a temporary file which we can delete once we have assigned it. Microsoft Office Outlook® Mobile stores the image internally so we don’t need to take up space explicitly storing the contact image files except during the sync process. Obviously downloading large quantities of images will use network bandwidth, so use common sense when the device is connected to a paid network.

The following code snippet shows the synchronization code:

private void mnuSync_Click(object sender, EventArgs e)
{
   foreach (ListViewItem lvi in lvFriends.Items)
   {
      Contact c = null;
      User u = (User)lvi.Tag;

      //lookup the user in poom
      ContactCollection matches = 
         session.Contacts.Items.Restrict("[FirstName] = \"" + u.FirstName 
         + "\" AND [LastName] = \"" + u.LastName + "\"");
                
      if (matches != null && matches.Count > 0)
      {
         c = matches[0];
      }
      else
      {
         //add a new contact
         c = session.Contacts.Items.AddNew();
         c.FirstName = u.FirstName;
         c.LastName = u.LastName;

         //mark this as a facebook contact
         c.Categories = "Facebook";
      }

      //create temp filename
      string filename = 
         System.IO.Path.Combine(System.IO.Path.GetTempPath(), 
         u.UserId + ".jpg");

      //delete if it exists
      if (System.IO.File.Exists(filename))
      {
         System.IO.File.Delete(filename);
      }

      //save and assign image
      u.PictureBig.Save(filename, 
         System.Drawing.Imaging.ImageFormat.Jpeg);
      c.SetPicture(filename);

      //delete temp file (outlook stores a copy)
      System.IO.File.Delete(filename);

      //store userid for future reference
      c.Properties.Add("Facebook.UserId", typeof(string));
      c.Properties["Facebook.UserId"] = u.UserId;

      //save the contact
      c.Update();

   }
}

Working with Events

Facebook supports user created calendar events that you can create for any purpose. These are not to be confused with .NET events, and are more analogous to calendar appointments in Outlook Mobile. You can invite friends or you can create public events that anyone can register their attendance at. Through the Facebook API, you can retrieve details on all the events to which you are invited (or have created). You can also view the current attendance (Attending, Not Attending, and so on) of members. You cannot create or modify events via the Facebook API. Our next sample application, DeviceEventSample, will show how to retrieve event details. We display the list of events returned from Facebook in a ListView control, including the image for the event. The screen is illustrated in Figure 6. Because the event images are not a specific aspect ratio some stretching occurs in the sample. The solution to this is to use an alternative control for display, such as an owner-drawn list control, or to copy the image into a presized canvas to ensure all the images have the same proportions. Because this sample is designed to show you the Facebook API, we leave it as an exercise for the reader to come up with a prettier user interface.

Bb932386.b6385c73-cd44-49ee-a1b1-c68070d2db38(en-us,MSDN.10).png

Figure 6. Facebook Events

We can see that working with the collection of FacebookEvent items is easy. One of the cool things you can do with this information is to use Outlook Mobile to store a copy of the events in your Calendar. This allows you use all the usual facilities for reminders and will show upcoming events on your Today/home screen. I have added a ContextMenu to the form and have associated the ContextMenu with the ContextMenu property on the ListView control. When the ContextMenu is tapped, we first check that an item is currently selected, we then run the AddToCalendar method:

private void AddToCalendar()
{
      foreach (int i in lvEvents.SelectedIndices)
      {
            if (i > -1)
            {
                  Appointment eventAppointment = null;
                  FacebookEvent fe = (FacebookEvent)lvEvents.Items[i].Tag;
                  Collection<EventUser> attendees = 
                        facebookService1.GetEventMembers(fe.EventId);

                  //check if it exists - if so update it
                  AppointmentCollection appointments = 
                        os.Appointments.Items.Restrict("[Categories] = \"Facebook\"");

                  foreach (Appointment a in appointments)
                  {
                        if ((string)a.Properties["Facebook.EventId"] == fe.EventId)
                        {
                              eventAppointment = a;
                              break;
                        }
                  }

                  //if not found add a new entry    
                  if(eventAppointment == null)
                  {
                        eventAppointment = os.Appointments.Items.AddNew();
                        eventAppointment.Categories = "Facebook";
                        //add the event id in a custom property
                    eventAppointment.Properties.Add("Facebook.EventId", 
                            typeof(string));
                        eventAppointment.Properties["Facebook.EventId"] = fe.EventId;                        
                  }
                    
                  eventAppointment.Subject = fe.Name;
                  eventAppointment.Location = fe.Location;
                  eventAppointment.Body = fe.Description;
                  eventAppointment.Start = fe.StartDate;
                  eventAppointment.End = fe.EndDate;
                  RecipientCollection rc = eventAppointment.Recipients;
                  //clear current list
                  for (int irecipient = rc.Count-1; irecipient > -1; irecipient--)
                  {
                        rc.Remove(irecipient);
                  }
                  foreach (EventUser eu in attendees)
                  {
                        if (eu.Attending == RSVPStatus.Attending)
                        {
                              //add recipient entries (no valid email addresses)
                              Recipient r = rc.Add(new Recipient(eu.User.Name, 
                                    "facebook"));
                        }
                  }
                  eventAppointment.Update();
            } 
      }
}

As well as setting a few of the standard properties on an Appointment there are a couple of items that deserve additional explanation. The first is that you’ll notice we have assigned the “Facebook” category to all programmatically created items. This makes it easier to search for existing items in the calendar that are Facebook items. Next we have taken advantage of a feature in the Pocket Outlook API ** in Windows Mobile 5.0 and beyond where we can add custom properties to items. We can use this mechanism to attach the eventid from Facebook to the item. I have called the property “Facebook.EventId” to make it unique as “EventId” could conceivably be used for another purpose. Finally we take advantage of Outlook Mobile’s support for meeting items. We have populated the meeting recipient collection with the names of all the confirmed attendees for the event. This is just for display; these cannot be used like traditional Outlook recipients to a meeting (where you can update a Meeting and inform the recipients) because the Facebook API does not expose e-mail addresses. It is purely used as a convenient method to store the attendees within the existing Appointment dialogs. Once the event is created it will synchronize with Outlook on the desktop and the user can do all the things they expect to do with the item, such as beam it over infrared or Bluetooth, or set an audible reminder. Figure 7 shows the created Appointment item in the Calendar application.

Bb932386.3724b041-13be-492f-8bfb-e4c337e183df(en-us,MSDN.10).png

Figure 7. Facebook event in Calendar

Working with Photos

Facebook allows its users to create multiple photo albums and upload up to 60 photos into each. It also allows you to add tags to images to show which of your friends are present in the image. There are some operations that cannot be performed through the Facebook API—you cannot delete or modify albums or photos. When you add a new photo it is invisible to other users. You must activate the picture from the Facebook Web site before it shows normally in your albums. The sample application for this section is a tool to browse and manage your own photo albums.

The main form of the application uses a ListView control to display a thumbnail image of each album. Figure 8 shows the opening form with a set of albums.

Bb932386.531f8d34-f964-4401-89a3-23ead9eabfef(en-us,MSDN.10).png

Figure 8. Facebook Photos

When the user selects a specific album, we then open up a new form showing all the photos in that album. From the main form you can also add a new album and view the properties of the currently selected album—Name, Location, and Description. Tapping New Album opens a new instance of the AlbumPropertiesForm where you can enter album information. When the form is closed (by tapping OK) the API is called to create a new album:

private void AlbumPropertiesForm_Closing(object sender, CancelEventArgs e)
{
      if (isnew)
      {
            if(!string.IsNullOrEmpty(txtName.Text))
            {
                  Album newAlbum = parent.facebookService1.CreateAlbum(
                        txtName.Text, txtLocation.Text, txtDescription.Text);
            }
      }
}

When the user returns to the main form, we refresh the album listing. When an album is created it is instantly visible in the user’s album collection, even if it contains no images.

When an album is selected we open a new instance of AlbumForm passing the album details. The AlbumForm is designed in a similar way to the main form, for simplicity we are using the built-in ListView control. The photos are loaded in the Load event handler for the form:

private void AlbumForm_Load(object sender, EventArgs e)
{
      Cursor.Current = Cursors.WaitCursor;
      lvAlbum.BeginUpdate();

      Collection<Photo> photos =
            parentForm.facebookService1.GetPhotos(album.AlbumId);
      int i = 0;
      foreach (Photo p in photos)
      {
            ListViewItem lvi = new ListViewItem(p.Caption);
            lvi.ImageIndex = i;
            ilAlbum.Images.Add(p.PictureSmall);
            lvAlbum.Items.Add(lvi);
            i++;
      }
      lvAlbum.EndUpdate();
      Cursor.Current = Cursors.Default;
}

Again the aspect ratio of the pictures can vary and so the presentation here with a ListView and ImageList results in some distorted images. However it provides a quick rendition of the album contents. Figure 9 shows the appearance of a typical album.

Bb932386.3c42b4e5-b689-40ef-aa93-18a5e69e9609(en-us,MSDN.10).png

Figure 9. Album form

There is one menu item on this form that allows you to upload a new image to the album. Unlike creation of a new album, a newly uploaded photo remains invisible until you authorize it from the Facebook Web site. When you view the album on the Web site it will show a pending items listing for those awaiting approval. You cannot approve images from the mobile version of the Web site. To integrate capture of the image we use the CameraCaptureDialog from the Microsoft.WindowsMobile.Forms assembly.

private void mnuPhoto_Click(object sender, EventArgs e)
{
      Microsoft.WindowsMobile.Forms.CameraCaptureDialog ccd = 
            new Microsoft.WindowsMobile.Forms.CameraCaptureDialog();
      ccd.Mode = Microsoft.WindowsMobile.Forms.CameraCaptureMode.Still;
      ccd.Title = "Add photo to Facebook";
      ccd.Resolution = new Size(640, 480);

      //if success
      if (ccd.ShowDialog() == DialogResult.OK)
      {
            System.IO.FileInfo fiImage = new System.IO.FileInfo(ccd.FileName);
            parentForm.facebookService1.UploadPhoto(album.AlbumId, fiImage);
      }
}

The UploadPhoto method takes an albumid and a FileInfo that contains the details of the image file. The FileInfo constructor is passed the full file path from the camera dialog.

Conclusion

In the samples explored in this article we have seen how to use the functionality exposed by the Facebook Developer Toolkit. Although Facebook does not expose the full functionality of the site through their API, they provide a wide range of functions for retrieving information on your friends, groups, events, and photos. We have seen how to take advantage of Windows Mobile APIs to integrate Facebook data with our device Contacts and Calendar applications. Finally we saw how to browse and upload to your online photo albums directly from your mobile device.

See Also

Facebook development has generated a lot of buzz recently. One interesting example is a desktop application called OutSync. It works with Outlook on the desktop to synchronize Facebook profile pictures with your contacts, which can then be synchronized with your Windows Mobile device. This is similar in concept to the code we have created above; additionally it has a rich Windows Presentation Foundation (WPF) user interface. A video demonstrating the product is available at Channel 10: https://www.on10.net/Blogs/laura/sync-your-facebook-contacts-with-outlook-and-windows-mobile/

Author Bio

Peter Foot is the founder of In The Hand Limited, a company providing software development and consulting services for mobile devices. In The Hand also produces award-winning software components for the .NET Compact Framework to assist other developers. In 2007 Peter co-authored the Microsoft Mobile Development Handbook published by Microsoft Press®.

Peter established the 32feet.NET shared-source community project bringing Bluetooth and IrDA technologies into easy reach of .NET developers. Peter has also been an active contributor to several other shared-source initiatives.

Prior to working with Windows Mobile, Peter led a test team for a mobile Internet portal in Great Britain on the first consumer GPRS service in Great Britain. Peter holds a BSc in Computer Science.