Jump to content

How to search Facebook using C#

+ 1
  JonUdell's Photo
Posted Nov 04 2010 06:22 AM

Introduction

In this week's companion article on the Radar blog, I discuss how principles of common-sense information architecture govern whether public events posted to Facebook will or won't be found by search. Here I'll show how the elmcity service, which recently added Facebook to its set of event sources, uses the Facebook search API.

Encapsulating Facebook's search API

This method wraps a call to the Facebook API. The RetryExpectingOK method uses the retry logic I developed in How to retry generically in C#.


    public string CallFacebookApi(string method, string args)
    {
      //  http://graph.facebook.com/search?q={QUERY}&type=event&access_token=xxx
      try
      {
        var key = this.apikeys.facebook_api_key;
        string host = "https://graph.facebook.com";
        string url = string.Format("{0}/{1}?access_token={2}&type=event&{3}",
          host, method, key, args);
        GenUtils.LogMsg("info", url, null);
        var request = (HttpWebRequest)WebRequest.Create(new Uri(url));
        var response = HttpUtils.RetryExpectingOK(request, data: null, wait_secs: this.wait_secs, 
          max_tries: this.max_retries, timeout_secs: this.timeout_secs);
        return response.DataAsString();
      }
      catch (Exception e)
      {
        GenUtils.LogMsg("exception""CallFacebookApi", e.Message + e.StackTrace);
        return "";
      }
    }

Unpacking Facebook results

In How to search Google and Bing in C# I used a third-party library, Json.NET, to unpack JSON results from those two search engines. Here I'm using one of the .NET Framework's built-in deserializers, System.Web.Script.Serialization.JavascriptSerializer.


    // using the built-in json deserializer here, in contrast to the 3rd party newtonsoft.json
    public IEnumerable<FacebookEvent> FacebookIterator(string method, string args)
    {
      var json = CallFacebookApi(method, args);
      var serializer = new System.Web.Script.Serialization.JavascriptSerializer();
      var dict = (Dictionary<stringobject>)serializer.DeserializeObject(json);
      var items = (Object[])dict["data"];
      foreach (Dictionary<stringobject> item in items)
      {
        var name = (string)item["name"];
        var location = (string)"";
        try { location = (string)item["location"]; }
        catch { };
        var start_time = (string)item["start_time"];
        var id = (string)item["id"];
        yield return new FacebookEvent(name, location, start_time, id);
      }
    }

What's the difference between the two? Consider this JSON fragment from Facebook:


{
   "data":[
      {
         "name":"Tiff Jimber in Keene, NH",
         "start_time":"2010-11-20T03:00:00+0000",
         "end_time":"2010-11-20T06:00:00+0000",
         "location":"Fritz's Place",
         "id":"151905824833190"
      },
      {
         "name":"World History @ Starving Artist (Keene NH)",
         "start_time":"2010-11-15T04:00:00+0000",
         "end_time":"2010-11-15T07:30:00+0000",
         "location":"The Starving Artist",
         "id":"100599506662874"
      },
      {
         "name":"Opening of Waxy Oconnor's at Best Western keene, NH",
         "start_time":"2010-11-05T18:00:00+0000",
         "end_time":"2010-11-05T19:00:00+0000",
         "location":"Best Western Keene, NH",
         "id":"138781362811592"
      }
   ],
   "paging":{
      "previous":"https://graph.facebook.com/search?access_token=xxx&type=event&q=keene%2Cnh&since=2011-01-01T04%3A00%3A00%2B0000&limit=1000",
      "next":"https://graph.facebook.com/search?access_token=xxx&type=event&q=keene%2Cnh&limit=1000&until=2010-11-05T17%3A59%3A59%2B0000"
   }
}

Let's load this fragment using both JSON deserializers and compare access styles:


    var s = File.ReadAllText("fb.json");
    var j_obj = (JObject)JsonConvert.DeserializeObject(s);
    var serializer = new System.Web.Script.Serialization.JavascriptSerializer();
    var n_obj = serializer.DeserializeObject(s);

Using the native .NET object, this expression will yield the first title, "Tiff Jimber in Keene, NH":

( ( Dictionary<string,object>) ( (Object[]) ( (Dictionary<string,object>) n_obj )["data"] ).First() )["name"]

Here's the equivalent -- and clearly more concise -- Json.NET expression:

j_obj["data"].First()["name"].Value<string>()

Json.NET also supports LINQ, you can gather the results like so:


    var results_query =
      from result in j_obj["data"].Children()
      select new FacebookEvent(
        name: result.Value<string>("name").ToString(),
        location: result.Value<string>("location").ToString(),
        start_time: result.Value<string>("start_time").ToString(),
        id: result.Value<string>("id").ToString()
        );

I generally prefer Json.NET, but it does create an extra dependency. In the end, it's not that much harder to use the built-in deserializer. Either way, I always have to do a bit of head-scratching to figure out how to navigate the graphs produced by these deserializers and how to cast their objects to .NET types. That's part of the reason I write these answers: So I can look them up myself!



Tags:
0 Subscribe


2 Replies

0
  ShahidNaeem's Photo
Posted Nov 10 2010 12:14 PM

great article on facebook api in C#. I have one question. How many posts can i get from a wall. is there any limit for maximum posts and what is maximum date range i can specify to get the posts from wall.

Thanks,

Shahid Naeem
0
  dbjdbj's Photo
Posted Nov 06 2012 09:33 AM

I understand this was 2010 ...but still "Why C#" ? It might be worth it to rewrite the whole of elmcity.cloudapp.net in WinJS on W8, and discuss the whole experience ... me thinks ...