使用 .NET 开发 Facebook 应用程序 - 第二部分
使用 .NET 开发 Facebook 应用程序 - 第二部分 - FBML 标签页,setFBML,FB:multi-friend-selector,setRefHandle,PublishAction 等等...
引言
《使用 ASP.NET 开发 Facebook 应用程序》系列下一篇文章(希望是最后一篇 :)
背景
简要回顾 使用 ASP.NET 开发 Facebook 应用程序 - 第一部分 以及 使用 ASP.NET 开发 Facebook 应用程序 - 第二部分 中的内容
如何 设置 Facebook 应用程序,然后使用 .NET (ASP.NET, C#) 中的 FBML(
CanvasFBMLBasePage
)来创建基于 FBML 的 Facebook 应用程序画布。第一部分演示了使用 FBJS 配合 FBML 和 .NET,展示了 使用 FBJS 对话框、AJAX 和 ASP.NET (C#) 进行动态内容更新,以及如何允许用户通过 使用 .NET 发送 Facebook 通知 - FBService.SendNotification()
进行交互,还包括如何使用 `<fb:iframe>` 配合 ASP.NET 和 FBML 包含外部页面在“使用 .NET 进行 Facebook 开发”系列的第二部分中,将介绍更多关于使用视觉元素的内容,例如 使用 FBML 标签页 和 使用 FBML 多好友选择器构建邀请页面(以及 使用 <fb:request-form/>)。
第二部分还展示了如何在 ASP.NET 中使用 FQL 来选择用户信息;以及如何使用 应用程序配置文件框和 FBML -
<fb:subtitle/>
、<fb:wide/>
、SetFBML()
、<fb:ref/>
和 SetRefHandle()
来更新 Facebook 用户配置文件。然后,展示了如何使用 fbml.setRefHandle()
和 Windows 任务计划程序中的简单 VBS 程序 来创建“定时任务”,定期更新 Facebook 用户配置文件页面。此外,还演示了如何使用
PublishAction()
(使用 Feed.publishActionOfUser
)填充 Facebook 用户迷你动态。最后,介绍了如何在 Facebook 中使用 ASP.NET 的
Post Remove URL
。使用 .NET 开发 Facebook 应用程序 -
使用 FBML 标签页
由于我将我“最棒的 Facebook 应用程序”设置为 FBML - CanvasFBMLBasePage,我几乎可以在 ASP.NET 页面中包含任何 FBML 标签或 FBML 元素。在 第一部分 中,我使用了 ASP.NET 中的 `<fb:dashboard>`。这里有一个不同的例子,用于创建类似 Facebook 的界面 - 创建一个如下所示的“标签页”用户界面
要创建类似 Facebook 的“标签页”界面,我使用了 `<fb-tabs/>`(有关更多信息,请参阅 FB:Tabs)- 我们可以在 ASP 页面中直接使用 FBML `<fb-tabs/>` 标签
<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>
当然,如果您的 Facebook“杰作” 包含超过两页,您显然可以使用 ASP.NET 指令 `<!--#include -->`。例如,类似于 `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>
构建邀请页面 - 使用 FB:multi-friend-selector
我在网上看到不少关于“如何构建像 Facebook 一样的邀请页面”的问题。**答案就是** - 您不需要。Facebook 平台为我们提供了这个功能 - 我们只需要重复使用它。
为了引用和显示 Facebook FBML 多好友选择邀请工具,我需要引用 `<fb:multi-friend-selector` 元素(有关更多信息,请参阅 Fb:multi-friend-selector)。但是,`<fb:multi-friend-selector` 必须在 `<fb:request-form>` 中使用(这背后有合乎逻辑的原因 - 用户需要将选择提交回服务器,因此需要使用表单)。我们可以像使用其他 FBML 或 HTML 元素一样,在 ASP.NET 页面中直接包含 `<fb:multi-friend-selector` 和 `<fb:request-form>`。但在我的示例应用程序中,我是通过代码构建的(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='https://#/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;
}
}
- 首先,是 `<fb:request-form>` 元素(更多信息请参阅:Fb:request-form)
- `type` 属性 - 只是显示在邀请表单上的标题
- `invite` 属性 - = true - 是的,我正在发送邀请
- `action` 属性 - 用户在提交 `<fb:request-form>` 后将被导向到此页面
- `content` 属性 - 显示在邀请表单上的 FBML 代码。`content` 属性还包含 `<fb:req-choice>` 元素。(有关更多信息,请参阅 Fb:req-choice)

从上面的示例中可以看到,我在 `content` FBML 中包含了 `<fb:name/>` 元素,以创建更具个性化的邀请。
- 其次,是 `<fb:multi-friend-selector/>` 元素(更多信息请参阅:Fb:multi-friend-selector)
- `actiontext` 属性 - 显示在选择邀请上的标题文本
- `showborder` 属性 - 是否显示边框?
- `rows` 属性 - 在 `<fb:multi-friend-selector/>` 元素中显示的好友行数。

无需复杂的编码,我们就可以包含大家都在谈论的同一个 Facebook 邀请表单。用户的“好友”将收到一个请求邀请,如下所示:

使用相同的方法,您还可以包含 `<FB:friend-selector/>`(请参阅 第一部分中的 FB:friend-selector 示例),或 `<fb:multi-friend-input/>`(请参阅 Fb:multi-friend-input)
使用 Facebook 查询语言 (FQL) - 为邀请页面构建查询
在前一节中,我们看到了如何包含 FBML 邀请“构造器”来显示邀请页面。但是,如果注意到了,“原样”版本显示的是用户的所有好友。
如果您要为用户提供邀请其好友使用您的 “至尊应用程序” 的方式,您不需要显示**所有**好友 - 而是只显示那些尚未安装您的 应用程序 的好友(他们怎么能不呢?!)。总之,我们需要找到谁已经安装(添加)了应用程序,然后将其排除在邀请列表之外。
要查找此类信息,我们可以使用 Facebook Developer Toolkit 库 中的 `GetFriendsAppUsers()` 方法(太简单了!),或者我们可以通过 **Facebook 查询语言 - FQL** 对 Facebook 数据运行选择查询。
**\* 旁注**:我不知道如何通过 Facebook API 查找某个应用程序的所有用户 - 包括好友和非好友。但我很想知道...
总之,要选择并获取已安装该应用程序的好友的用户 ID 列表,我们需要引用两个 Facebook 表 `User` 和 `Friend`:
在此查询中,`has_added_app = 1` - “where”子句部分 - 告知 Facebook 我们只需要已安装此应用程序的用户(因此,如果我想查找尚未添加我的应用程序的好友,我需要在“where”子句中使用 `has_added_app = 0`)。
而 `uid in (select uid2 from friend where uid1 ....` 部分 - 表明我们只需要给定用户的好友(有关更多信息,请参阅 FQL“在线手册”,以及 FQL 表)。
在上面的查询中,我们只选择 `uid` 字段,因为这是我们唯一需要传递到 `<fb:multi-friend-selector` 元素的。但我们可以使用 Facebook FQL 提取更多信息 - 例如姓名、图片、兴趣等(请参阅 Facebook 用户表 (FQL) 的完整列表)。顺便说一下,您可以尝试在 Facebook FQL 引擎上测试您的查询命令,并在 Facebook 测试控制台 上查看返回的数据。

回到在 ASP.NET/C# 中使用 Facebook 查询语言。
要实际执行 FQL 查询并检索数据 - 例如获取包含使用您的应用程序的好友列表的数据集
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;
}
}
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;
}
}

列表也可以用于 `<fb:multi-friend-selector/>` 元素 - 以排除已安装应用程序的好友。为此,我们需要引用 `<fb:multi-friend-selector` 元素的 `exclude_ids` 属性。
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='https://#/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;
}
}
(另外,在您的应用程序中,您可能需要检查给定用户是否有任何好友,或是否有任何没有安装应用程序的好友 - 也许您不需要显示邀请表单,只需告诉用户先**找到**更多好友:

...
//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;
}
...
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;
}
}
使用 ASP.NET 中的 FBML 更新/显示用户个人资料页上的应用程序配置文件
到目前为止,我们已经成功地在应用程序画布页面上显示了非常非常重要的信息。然而,通常除了在应用程序画布页面上显示信息外,我们还需要通过**用户个人资料页**让用户知道发生了什么 - 使用**应用程序配置文件框**、**迷你动态**和/或**新闻/故事动态**(另请参阅 - Facebook Developers Wiki 上的更改个人资料内容)。
让我们看看如何使用 FBML 元素更新**用户个人资料页**并填充应用程序配置文件框。
为了在**用户个人资料页**上显示和/或更新应用程序信息,
- 我们需要引用以下 FBML 元素和方法。
- `<fb:subtitle/>` - 定义配置文件框的副标题(有关更多信息,请参阅 `<fb:subtitle/>`),
- `<fb:wide/>` - 定义仅在配置文件框显示在个人资料的宽列中时出现的内容(有关更多信息,请参阅 `<fb:wide/>`),
- `SetFBML()` 方法用于显示应用程序配置文件框(有关更多信息,请参阅 `Profile.setFBML()`),以及
- `<fb:ref/>`(有关更多信息,请参阅 `<fb:ref/>`),以及
- Facebook API 方法 `SetRefHandle()`(有关更多信息,请参阅 `Fbml.setRefHandle()`)。
FBML 应用程序不知道用户何时加载他们的**用户个人资料页**,因此为了让 Facebook 知道我们需要更新**用户个人资料页**上的信息,我们可以使用 `SetRefHandle()` 方法进行后续更新。
- 为此,事件顺序是:
- 应用程序画布正在加载,
- 执行 Page_Load(),
- Page_Load() 调用 `SetFBML()`,
- `SetFBML()` 使用 `<fb:ref/>` 创建并设置后续更新的引用句柄,
- 然后,当需要更新时,我们只需调用 `SetRefHandle()` 并传递 #4 中创建的引用句柄。
所以,让我们看看如何在 ASP.NET 和 C# 中实现。
首先,Page_Load() 调用 `SetFBML()` 来创建和设置引用句柄。
...
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
...
}
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;
}
例如,当应用程序中发生某个事件时,应用程序可以告知 Facebook 更新用户配置文件。
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);
...
}
为此,创建一个简单的 ASP.NET 页面(例如 `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);
}
}
例如,使用这样的 VBS 文件:
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
在 ASP.NET 中使用 FBML 和 Facebook API 创建迷你动态
现在,如果您真的想“刷屏”**用户个人资料页**,您可以发布(创建)用户迷你动态下的条目:
为此,Facebook API 有一个 `Feed.publishActionOfUser` 方法(有关更多信息,请参阅 `Feed.publishActionOfUser()`),在 Facebook Developer Toolkit 库中,我们需要引用 `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);
...
}
...
...
}

与更新个人资料一样,您也可以使用 Windows 任务计划程序来安排迷你动态条目发布过程(请参阅上面的示例 `fbml.setRefHandle()` 和 Windows 任务计划程序中的简单 VBS 程序)。
处理 Facebook 应用程序卸载 - 使用 Post Remove URL
与任何应用程序一样,用户不仅倾向于安装应用程序,也倾向于**卸载**它们(该死的混蛋,怎么能这样?!)。
Facebook 平台允许开发者跟踪应用程序移除事件(哈,如果您想派黑手党去抓这些用户),方法是使用 Facebook 开发者应用程序设置中的**Post Remove URL** 字段:
正如您所见,您只需要引用一个 ASP.NET 页面(或 ASP 页面),该页面将处理来自 Facebook 的 **POST** 请求,即当用户卸载应用程序时,Facebook 会向该 URL 发送一个 **POST** 请求(有关更多信息,请参阅 Post-Remove URL)。
并处理 Facebook 应用程序移除请求。
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?
}
}
}
历史
在此处保持您所做的任何更改或改进的实时更新。