Monday, December 01, 2008

Extending facebook.net to work with the latest feed publishing API

When I wrote my first facebook applications last year I used the lovely and very convenient facebook.net platform.

However, facebook has changed a lot since then, and sadly it appears facebook.net isn't keeping up - in fact it looks quite dead as a project...

So I thought I'd have a go at hacking in some new functionality....

In particular, I wanted to extend my application to use the publishUserAction API - especially as the old publish APIs seem to have been deprecated and disabled by facebook.

To do this, I:

  1. Used the Feed Template Console to build a very simple template for me new message.

    • Basically I created a feed template with just a "Primary One Line Template" which was "{*actor*} {*rawText*}"
    • For all other options (short story, full story, etc) I just pressed "skip".
    • In the last step of this console, facebook gave me the template id, let's call this 1234.

  2. Using the excellent (essential!) reflector I broke apart facebook.net - please note, this is open source anyway so I wasn't doing anything naughty here!
    • From the facebook.net dll I took the JsonWriter class - plus I needed to borrow IndentedTextWriter and some constants from JsonReader.
    • From the facebook.net dll I looked at the existing code for FeedService.PublishTemplatedStory and decided to adapt this for my needs.

  3. I created a new method called HackPublishTemplatedStory and wrote it's content as:
    /// #summary
    /// New publish story mechanism - see http://slodge.blogspot.com for details
    /// #/summary
    /// #param name="body"
    /// #returns
    private bool HackPublishStory(string body)
    {
    // see http://wiki.developers.facebook.com/index.php/Feed.publishUserAction
    string method = "feed.publishUserAction";

    if (string.IsNullOrEmpty(body))
    {
    throw new ArgumentNullException("body");
    }

    FacebookRequest request = new FacebookRequest(myFacebookApp.Session);
    request.Parameters["template_bundle_id"] = "1234";

    Hashtable h = new Hashtable();
    h["rawText"] = body;

    StringBuilder sb = new StringBuilder();
    HackJsonWriter tempWriter = new HackJsonWriter(new System.IO.StringWriter(sb), true);
    tempWriter.WriteValue((IDictionary)h);
    request.Parameters["template_data"] = sb.ToString();

    FacebookResponse response = request.InvokeMethod(method);
    return ((response.Status == FacebookResponseStatus.Succeeded) && HackCoerceBoolean(response.Result));
    }
  4. Plus I added some simple code for HackCoerceBoolean:

    internal static bool HackCoerceBoolean(object o)
    {
    if (o is bool)
    {
    return (bool)o;
    }
    if (o is int)
    {
    return (((int)o) == 1);
    }
    if (o is string)
    {
    return (string.CompareOrdinal((string)o, "1") == 0);
    }
    return ((o is ArrayList) && ((bool)((ArrayList)o)[0]));
    }

  5. I could then call this in code using lines as simple as:

    HackPublishStory(string.Format("sent a Christmas Poke to #fb:name uid=\"{0}\" /#", targetFriendId));
    (please excuse the # marks in this line of code - I'm fighting blogger's HTML editor!)

  6. That's it!
If you want to see it in action try Christmas Poke for real on Facebook - although I must stress it was my first ever app! (And I'm sure there are still facebook bugs in there)

1 comment: