Developing Facebook Application with .NET - part 2
Developing Facebook Application with .NET - part 2 - FBML tabs, setFBML, FB:multi-friend-selector, setRefHandle, PublishAction and much more...
Introduction
Next article in "Facebook Application Development with ASP.NET" series (hopefully last one :) )
Background
Short recap of Facebook Application Development in ASP.NET - Part 1 and what's in Facebook Application Development in ASP.NET - Part 2:
how to Setup Facebook Application, and then use FBML in .NET (ASP.NET, C#) -
CanvasFBMLBasePage
- to create a FBML-based Facebook Application canvas.
Part 1 demonstrated using
FBJS
with FBML and .NET,
showing dynamic content using FBJS Dialog, AJAX and ASP.NET (C#),
and how to allow user interactions with sending Facebook Notifications in .NET - FBService.SendNotification()
,
and also how to include an external page using <fb:iframe> with ASP.NET and FBML
in Part 2 of "Facebook Development with .NET" series, more of using visual elements, such as using FBML Tabs and building Invite page with FBML multi friend selector (and using <fb:request-form/>).
Part 2 also shows using FQL in ASP.NET to select user information; and how to update Facebook user profile using Application profile box and FBML -
<fb:subtitle/>
, <fb:wide/>
, SetFBML()
, <fb:ref/>
and SetRefHandle()
.
Then, how to create a "cron job" to update Facebook user profile page on regular basis using
fbml.setRefHandle()
and simple VBS program in Windows Task Scheduler.
Also, how to populate Facebook User mini-feeds with
PublishAction()
(using Feed.publishActionOfUser
)
.
And finally using
Post Remove URL
in Facebook with ASP.NET.
Developing Facebook Application with .NET -
using FBML tabs
Because I set my greatest Facebook Application as FBML - CanvasFBMLBasePage,
I can include pretty much any FBML tag, or FBML element in ASP.NET page -
In Part 1,
I used
<fb:dashboard>
in ASP.NET.
Here a different example to create a Facebook-alike interface - create a "tab"-ed user interface like this:
To create Facebook-like tab'-ed interface I'm using <fb-tabs/>
(see more at FB:Tabs) - we can use
FBML <fb-tabs/>
tag right in ASP page:
<fb:tabs>
<fb:tab-item href="http://apps.facebook.com/fbtestappsiccolo/" title="Home" />
<fb:tab-item href="http://apps.facebook.com/fbtestappsiccolo/app_users.aspx" title="Users" />
<fb:tab-item href="http://apps.facebook.com/fbtestappsiccolo/app_objects.aspx" title="Babies"
selected="true" />
<fb:tab-item href="http://apps.facebook.com/fbtestappsiccolo/app_invite.aspx" title="Invite"
align="right"/>
</fb:tabs>
<fb:tab-item
elements nested in <fb:tabs>
</fb:tabs>
.
Each <fb:tab-item
points to a tab source page using href
attribute.
To set <fb:tab-item
caption - using title
attribute. To set if particular tab is selected -
using selected
attribute. And last, if we need "move" tab all of way to the right -
using align
attribute: align="right".
(see more at Facebook Torah FB:Tabs)
And of' course, if your Facebook "magnum opus" includes more than two pages, you can obviously (or obivously) use
<!-- include -->
ASP.NET
directive. Something along these lines, for example, tabs_header.asp:
//asp.net page to include tabs:
<fb:tabs>
<fb:tab-item href="url1.aspx" title="URL#1"
<% if ( Request.ServerVariables["SCRIPT_NAME"].ToString().Contains("url1.aspx"))
{Response.Write ("selected=\"true\");}
%>
/>
<fb:tab-item href="" title="URL#2" />
</fb:tabs>
Building Invite page - using FB:multi-friend-selector
I see quite a few questions on 'net related to "how do I build Invite page, exactly like Facebook has".
And the answer is - you don't need to. Facebook platform has it for us - we just need to reuse it.
In order to reference and display Facebook FBML multi friend selection invite tool,
I needed to reference <fb:multi-friend-selector
element
(see more at Fb:multi-friend-selector).
But,<fb:multi-friend-selector
has to be used within <fb:request-form>
(this has a logical reason behind the madness - user needs to submit selection back to server,
hence the need of using a form).
We can inlcude <fb:multi-friend-selector
and <fb:request-form>
right in ASP.NET page, as with any other FBML or HTML element.
But in my sample application, I built it inside the code (snapshot of app_invite.aspx):
using Facebook;
using Facebook.WebControls;
public partial class _AppInvite : CanvasFBMLBasePage
{
private const string FACEBOOK_API_KEY = "0m0y0v0e0r0y1s1e1c2r3e4t9key";
private const string FACEBOOK_SECRET = "0evenmoresecretsekret1";
new protected void Page_Load
(object sender, EventArgs e)
{
base.Api = FACEBOOK_API_KEY;
base.Secret = FACEBOOK_SECRET;
this.FBService.ApplicationKey = FACEBOOK_API_KEY;
this.FBService.Secret = FACEBOOK_SECRET;
base.Page_Load(sender, e);
string errorInfo = String.Empty;
ShowApplicationInvite
(this.FBService.UserId);
}
private bool ShowApplicationInvite(string facebookUserID)
{
string inviteContent = "<fb:name uid='" + facebookUserID + "' firstnameonly='true' " +
" shownetwork='false' />" +
" Wants You to join 'Traveling Babies'; pass Babies Around!" +
"<fb:req-choice url='http://www.facebook.com/add.php?api_key=" + FACEBOOK_API_KEY + "' " +
" label='Pass Babies Around with Traveling Babies!' />";
inviteContent = Server.HtmlEncode(inviteContent);
string inviteForm = "<fb:request-form type=\"Traveling Babies\" invite=\"true\" method=\"POST\" "+
" action=\"http://apps.facebook.com/fbtestappsiccolo/\" "+
" content=\"" + inviteContent + "\">" ;
inviteForm += "<fb:multi-friend-selector actiontext=\"Give your Friend a Gift of Baby\""+
showborder=\"true\" rows=\"3\" "+
"/>";
inviteForm += "</fb:request-form>";
this.divFriendSelector.InnerHtml = inviteForm;
}
}
- First,
type
attribute - just a caption that is displayed on the invite forminvite
attribute - = true - yes, I'm sending the invitationaction
attribute - user is taken to that page after<fb:request-form>
is submittedcontent
attribute - FBML code that is displayed on the invite form.content
attribute also includes<fb:req-choice>
element. (see more at Fb:req-choice)
<fb:request-form>
element (more at: Fb:request-form)

As you can see from the above example, I'm including
<fb:name/>
element in content
FBML,
to create a more personalized invitation.
- Second,
actiontext
attribute - caption text that is displayed on the invite selectionshowborder
attribute - border anyone?rows
attribute - number of rows of friends to show in the<fb:multi-friend-selector/>
element.
<fb:multi-friend-selector/>
element
(more at: Fb:multi-friend-selector)

With no complex coding, we can include the same Facebook Invite form everybody is talking about. And user's Friend will receive a request invite, like this:

Using the same approach you can also include
<FB:friend-selector/>
(see FB:friend-selector example in Part 1),
or <fb:multi-friend-input/>
(see at Fb:multi-friend-input)
using Facebook Query Language (FQL) - building query for Invite page
In the previous section, we saw how to include FBML Invite "constructor" to show Invite page. But, if noticed, "as-is" version above shows all of User's Friends.
If you are to provide a way for a user to invite his/her Friends to use your "supreme application",
you don't need to display all of the Friends - instead, just the ones who haven't installed your
application (how could they not?!).
Bottom line is, we need to find who already installed (added) application, and then exlude from the Invite list.
To find such information, we can use GetFriendsAppUsers()
method (too easy!) from Facebook Developer Toolkit library,
or we can run a select query against Facebook data using Facebook Query Language - FQL.
* side note: I don't know how to find all the users of a particular application via Facebook API - friends and not-so-friends. But curious to find out...
Anyhow, to select and get a list of user ID's of Friends who installed the application already,
we need to reference two Facebook tables User
and Friend
:
string queryCommand = "select uid " +
" from
user
" +
" where has_added_app = 1 " +
" and uid in (select uid2 from friend
where uid1 = " + facebookUserID + ")";
facebookUserID
points to Facebook User ID of the current user using your application.
In this query, has_added_app = 1
- "where" clause part - tells Facebook that we only need users who installed this application
(so, if I need to find Friends who hasn't added my application, I need to use has_added_app = 0
in "where" clause).
And uid in (select uid2 from
part - that we only need Friends of a given user
(see more at FQL "Books Online", and
FQL Tables).
friend
where uid1 ....
In the above query we only select uid
field, because that's only one we need to pass into
"#fbml_multi_friend_select">fb:multi-friend-selector
element. But we could extract more information using Facebook FQL -
such as name, picture, interests etc (see full list at Facebook User table (FQL)).
By the way you can test your query command against Facebook FQL engine and see data returned at
Facebook Test console:
Back to using Facebook Query Language and ASP.NET/C#.
To actually execute FQL query and retrieve data back - for example get Dataset containing list of Friends using your application:
public bool GetApplicationUserFriends(string facebookUserID,
out DataSet queryResults,
out string errorInfo)
{
errorInfo = String.Empty;
queryResults = null;
try
{
//Facebook [User] table:
string queryCommand = "select uid " +
" from user " +
" where has_added_app = 1 " +
" and uid in (select uid2 from friend where uid1 = " + facebookUserID + ")";
bool result = ExecuteQuery
(queryCommand, out queryResults, out errorInfo);
if ( result && queryResults.Tables.Count > 0)
{
if (queryResults.Tables["user"] != null)
{ return true; }
}
return result;
}
catch (Exception ex_get_user_app_friend)
{
errorInfo = "Failed to GetApplicationUserFriends(dataset):" + ex_get_user_app_friend.Message;
return false;
}
}
ExecuteQuery()
method calls DirectFQLQuery()
of Facebook Developer Toolkit library:
public bool ExecuteQuery(string queryCommand, out DataSet queryResults, out string errorInfo)
{
errorInfo = String.Empty;
queryResults = null;
try
{
string xmlDataReturned = m_FacebookService.DirectFQLQuery
(queryCommand);
queryResults = new DataSet();
System.IO.StringReader xmlReader = new StringReader(xmlDataReturned);
queryResults.ReadXml(xmlReader);
return true;
}
catch(Exception ex_exec_query)
{
errorInfo = "Failed to exec [" + queryCommand + "]:" + ex_exec_query.Message;
return false;
}
}
DirectFQLQuery()
,
I can display list of users already who installed my application:

Same list can be used for
<fb:multi-friend-selector/>
element - to exclude Friends who installed application already.
For this, we need to reference exclude_ids
attribute of <fb:multi-friend-selector/>
element:
using Facebook;
using Facebook.WebControls;
public partial class _AppInvite : CanvasFBMLBasePage
{
private bool ShowApplicationInvite(string facebookUserID)
{
string inviteContent = "<fb:name uid='" + facebookUserID + "' firstnameonly='true' " +
" shownetwork='false' />" +
" Wants You to join 'Traveling Babies'; pass Babies Around!" +
"<fb:req-choice url='http://www.facebook.com/add.php?api_key=" + FACEBOOK_API_KEY + "' " +
" label='Pass Babies Around with Traveling Babies!' />";
inviteContent = Server.HtmlEncode(inviteContent);
string inviteForm = "<fb:request-form type=\"Traveling Babies\" invite=\"true\" method=\"POST\" "+
" action=\"http://apps.facebook.com/fbtestappsiccolo/\" "+
" content=\"" + inviteContent + "\">" ;
inviteForm += "<fb:multi-friend-selector actiontext=\"Give your Friend a Gift of Baby\" "+
" showborder=\"true\" rows=\"3\" "+
" exclude_ids=\"" + friendList + "\" "
+
"/>";
inviteForm += "</fb:request-form>";
this.divFriendSelector.InnerHtml = inviteForm;
}
}
friendList
variable contains list of Friend ID's extracted using the above query and DirectFQLQuery()
method
(also, in your application, you may want to check if given user has any friends, or any friends without the application - may be you don't need to show Invite form, just tell the user to find more friends first:

...
//do we have any friends without babies?
if (GetUserFriends_WithoutApplication(facebookUserID,
out friendList,
out errorInfo)
)
{
if (friendList == String.Empty)
{
//no friends without
this.divFriendSelector.InnerText = "Yahooooooooooooo! All of your friends are with baby!Get a life!";
return true;
}
}
else
{
return false;
}
...
GetUserFriends_WithoutApplication()
is something like this:
public bool GetUserFriends_WithoutApplication(string facebookUserID,
out DataSet queryResults,
out string errorInfo)
{
errorInfo = String.Empty;
queryResults = null;
try
{
//Facebook [User] table:
string queryCommand = "select uid " +
" from user " +
" where has_added_app = 0
" +
" and uid in (select uid2 from friend where uid1 = " + facebookUserID + ")";
bool result = ExecuteQuery(queryCommand, out queryResults, out errorInfo);
if (result && queryResults.Tables.Count > 0)
{
if (queryResults.Tables["user"] != null)
{ return true; }
}
return result;
}
catch (Exception ex_get_user_app_friend)
{
errorInfo = ex_get_user_app_friend.Message;
return false;
}
}
has_added_app = 1
, I used has_added_app = 0
to get list of users who are Friends but don't have application added.
using FBML in ASP.NET to update/show Application Profile on User Profile Page
So far we have managed to display very-very important information on application canvas page. Usually, though, in addition to show information on application canvas page,
we also need to let user know what's going on via User Profile page - using Application Profile box, mini-feeds and/or news/story feeds
(see also - Changing profile content at Facebook Developers Wiki).
Let's see how we can update User Profile page and populate Application Profile box using FBML elements:
In order to display and/or update application information on User Profile page,
we need to reference the following FBML elements and methods:
To display Application profile information on User Profile page, we need to call <fb:subtitle/>
- defines the subtitle for the profile box
(see more at <fb:subtitle/>
),
<fb:wide/>
- defines content that appears only when profile box is in the wide column of the profile
(see more at <fb:wide/>
),
SetFBML()
method to display Application profile box (see more at Profile.setFBML()
), and
<fb:ref/>
(see more at <fb:ref/>
), and
SetRefHandle()
(see more at Fbml.setRefHandle()
)
SetFBML()
method
(see more at Profile.setFBML()
), but we can only use setFBML()
method when our application is being called, i.e. when canvas page is being loaded.
FBML Application has no knowing of When user loads his/her User Profile page, so in order to let Facebook know that we need to update information on
User Profile page we can use SetRefHandle()
method for subsequent updates.
- For this, sequence of events is:
- Application canvas is being loaded,
- Page_Load() is executed,
- Page_Load() calls
SetFBML()
, SetFBML()
creates and sets reference handle for subsequent updates using<fb:ref/>
,- and then, when update is required, we just need to call
SetRefHandle()
and pass reference handle created in #4.
So, let's see how it can be done in ASP.NET and C#.
First, Page_Load() calls
SetFBML()
to create and set reference handle:
...
using Facebook;
using Facebook.WebControls;
...
public partial class _App : CanvasFBMLBasePage
{
...
...
base.Api = FACEBOOK_API_KEY;
base.Secret = FACEBOOK_SECRET;
base.Page_Load(sender, e);
...
...
string facebookUserID = this.FBService.GetUserInfo().UserId;
...
...
//set initial profile - empty profile with reference handle only:
//show in wide
string profileFBML = fbmlMaker.BuildInitialApplicationProfileFBML("Application status as of " +
System.DateTime.Now.ToShortTimeString());
FBService.SetFBML(profileFBML, "", null, facebookUserID);
//and send complete information via reference handle:
profileFBML =
fbmlMaker.BuildUpdatedApplicationProfileFBML("Application status as of " +
System.DateTime.Now.ToLongTimeString(),
"...some user information here...");
string handleUpdate = "announcement_" + facebookUserID;
FBService.SetRefHandle(handleUpdate, "<fb:wide/>");
FBService.SetRefHandle(handleUpdate, profileFBML);
//done with profile
...
}
fbmlMaker
is a little helper I have to "deal" with FBML:
public string BuildInitialApplicationProfileFBML(string subTitle)
{
string fbmlProfile = String.Empty;
//attach ref handle:
fbmlProfile += "<fb:ref handle=\"announcement_" + m_FacebookUserID + "\">";
fbmlProfile += "<fb:subtitle>";
fbmlProfile += subTitle;
fbmlProfile += "</fb:subtitle>";
return fbmlProfile;
}
public string BuildUpdatedApplicationProfileFBML(string subTitle, string profileInfo)
{
string fbmlProfile = String.Empty;
fbmlProfile += "<fb:subtitle>";
fbmlProfile += subTitle;
fbmlProfile += "</fb:subtitle>";
fbmlProfile += "<fb:wide>";
fbmlProfile += profileInfo;
fbmlProfile += "</fb:wide>";
return fbmlProfile;
}
SetRefHandle(handleUpdate, profileFBML)
will affect all users with that particular reference handle.
For example, when a certain event occured in the application, application can tell Facebook to update user profile:
protected void buttonSend_Click(object sender, EventArgs e)
{
...
string handleUpdate = "announcement_" + facebookUserID;
string updatedUserProfile =
fbmlMaker.BuildUpdatedApplicationProfileFBML("Updated Application status as of " +
System.DateTime.Now.ToLongTimeString(),
"Something just happened!");
FBService.SetRefHandle(handleUpdate, updatedUserProfile);
...
}
For this, create a simple ASP.NET page (for example
app_update_profile.aspx
):
using Facebook;
using Facebook.WebControls;
public partial class _AppUpdateProfile : CanvasFBMLBasePage
{
new protected void Page_Load(object sender, EventArgs e)
{
base.Api = FACEBOOK_API_KEY;
base.Secret = FACEBOOK_SECRET;
this.FBService.ApplicationKey = FACEBOOK_API_KEY;
this.FBService.Secret = FACEBOOK_SECRET;
// get list of Facebook User IDs from....database, for example, something like this:
DataSet dataApplicationUserList = null;
result = GetApplicationUsers(out dataApplicationUserList);
//for every known Facebook User - update thier profile:
foreach (DataRow dr in dataApplicationUserList.Tables[0].Rows)
{
//read Facebook User ID and user session from database
facebookUserID = dr["facebook_user_id"].ToString();
facebookUserSessionKey = dr["facebook_session_key"].ToString();
//set FBService, so it looks like that user:
this.FBService.SessionKey = facebookUserSessionKey;
this.FBService.UserId = facebookUserID;
//set reference handle:
string handleUpdate = "announcement_" + facebookUserID;
//construct updated profile:
string userProfileString = "This is wake up call for " +
"<fb:name uid=\"" + facebookUserID + "\" capitalize=\"true\" />";
string updatedProfileFBML = fbmlMaker.BuildUpdatedApplicationProfileFBML(profileTitle,
userProfileString);
//and send updated profile to Facebook:
this.FBService.SetRefHandle(handleUpdate, updatedProfileFBML);
}
}
For example, using such VBS file:
args = WScript.Arguments.Count
URL = "http://www.siccolo.com/articles/app_update_profile.aspx"
Set WshShell = WScript.CreateObject("WScript.Shell")
Set http = CreateObject("Microsoft.XmlHttp")
http.open "GET", URL, FALSE
http.send ""
WScript.Echo http.responseText
set WshShell = nothing
set http = nothing
using FBML and Facebook API in ASP.NET to create mini-feed
Now if you really want to "flood" User Profile page, you can post (create) entries under user's mini-feeds:
To do this, Facebook API has a method Feed.publishActionOfUser
(see more at Feed.publishActionOfUser()
), and
in Facebook Developer Toolkit library, we need to reference PublishAction()
:
using Facebook;
using Facebook.WebControls;
public partial class _AppUpdateProfile : CanvasFBMLBasePage
{
...
...
protected void buttonSend_Click(object sender, EventArgs e)
{
...
string updatedFeed = "... Updated Information ...";
System.Collections.ObjectModel.Collection images = new Collection();
images.Add(new Facebook.Entity.PublishImage("http://www.siccolo.com/fbtestappsiccolo/images/minifeed.jpg?11",
"http://apps.facebook.com/fbtestappsiccolo"));
string publish = FBService.PublishAction("Application update:", updatedFeed, images);
...
}
...
...
}

And, as with updating profile, you can also schedule mini-feed entry publishing process using Windows Task scheduler (see example above
fbml.setRefHandle()
and simple VBS program in Windows Task Scheduler).
Handle Facebook Application Uninstall - using Post Remove URL
As with any application, users have a tendency to not only install applications, but also un-install them (bloody bustards, how could they?!).
And Facebook platform allows a developer to keep track of application removal occurrences (ha, if you want to send mafia after these users),
by using Post Remove URL field under Facebook Developer Application settings:
As you can see, you just need to reference a ASP.NET page (or ASP page) that would handle POST request from Facebook, i.e.
Facebook will send a POST request to this URL when a user uninstalls the application
(see more at Post-Remove URL).
And to process Facebook Application remove request:
public partial class app_remove : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//facebook passes user_id
try
{
string facebookUserID = Request.Form["fb_sig_user"];
//having ID of Facebook User we can update database for example,
//or call and send them pizza...
}
catch //(Exception ex_remove_app)
{
//what do we do with the error?
}
}
}
History
Keep a running update of any changes or improvements you've made here.