Creating a New Facebook Canvas Application
The steps below will help you to create a functional ASP.NET Web site to be used as an IFrame canvas application featuring XFBML markup, the feed form, and integration with the Facebook API via the Facebook Developer Toolkit. The project will be built using Visual Studio 2008 and .NET Framework 3.5, although other platforms can also utilize the Facebook Platform.
Create a Facebook Application
In order to develop and integrate with Facebook, you must install the Facebook Developer Application to your Facebook Account. This application is used to manage custom application settings, publish the application and access the Facebook Platform.
- Login to Facebook.com
- Navigate to http://www.facebook.com/apps/application.php?id=2345053339 and install the application.
In the bottom-left corner of the page, click the
Developer application icon. At the top of the Developer page, click "Setup New Application". Enter the application name and agree to the terms of service. The resulting page is the management home for the new application. Take note of the API Key and Secret, which will be used by your site to access the Facebook API.
.jpg)
- Enter any desired application settings, icon images, etc.
- Navigate to the Canvas section of the application settings. Enter a Canvas Page URL, which will be the URL that users will use to visit your application.
- Enter the URL for the root of your site as the Canvas Callback URL. Make sure that it ends in a slash ("/"), otherwise Facebook may not deal with it correctly. Your application's canvas page will have an IFrame which will display the content at this URL. During development this can be set to the Visual Studio local port if desired. For example, the demo Web site will be configured to run on port 63919, therefore the Canvas URL is set as http://localhost:63919/.
Make sure the Render method is set to IFrame. Save the changes.
.jpg)
Navigate to the Connect tab and enter your Canvas URL as the Connect URL. This parameter will be used for cross domain communication, which is explained in more detail below. Save the changes.
.jpg)
- During development you may also wish to enable the Advanced tab's Sandbox Mode, which limits Facebook interaction to only the developer accounts listed in the application.
- Create Template Bundle
- Navigate to the Feed Template Console at http://developers.facebook.com/tools.php?feed
- Select your application in the drop-down and click Next.
Create a one line story template using the {*actor*} and {*color*} placeholder tokens. For example, I used "{*actor*} says that his or her favorite color is {*color*}!" When the template is used, {*actor*} will be replaced with the name of the user, and {*color*} will be the color they selected in the app (more on this later). In the Sample Template Data box, erase what's there and enter {"color":"green"}. Click Next.
.jpg)
- Click Skip on the Short Story template page.
On the Action Link page, enter some text to invite other users to use your application in the Action Link Text field, and enter your canvas URL in the Action Link URL field. Click Next.
.jpg)
- Click Register Template Bundle. When the success message pops up, copy the template bundle ID and save it somewhere for later on. If you close the popup too soon, you can find the template bundle ID at http://developers.facebook.com/tools.php?templates.
- Download and Open Sample
- Edit Settings in web.config
- In the project, open web.config. Near the top of the file, you should see some settings in the <appSettings> element. Change the values for those settings to the following:
- APIKey: your API key
- Secret: your application secret
- Callback: your callback URL
- Suffix: The suffix of your canvas page URL. For example, for a site located at http://apps.facebook.com/fdtiframesample/, the suffix is fdtiframesample.
- Edit Template Bundle ID
- Open Default.aspx. In the JavaScript towards the top of the page, there is a call to FB.Connect.showFeedDialog(). Change the first parameter to be your template bundle ID (in quotes). Normally this would be stored in your web.config, but it was stored here to make the code easier to read.
- Set Up Project Port Number
- Run Application
- Start the Web application (click Debug menu, click Start Debugging).
- Close the browser window that opens, since it doesn't open your app within the Facebook context.
- Navigate to your canvas page URL (http://apps.facebook.com/your-app-suffix).
- On the "Allow Access?" page, click "Allow".
- You now have a fully working Facebook IFrame canvas application. Enjoy!
Authentication
In this sample, I used the CanvasIFrameMasterPage to take care of authenticating the session with Facebook. This class takes care of the entire authentication process; all you have to do is give the application your API key and secret, as we did in the web.config above, as well as letting it know which pages require the user to have an authenticated session. It may be useful to allow certain pages to be viewed without an authenticated session so that users who have not yet added your application can see it and discover why it might be interesting to them. Also, some parts of the Facebook API are available without an authenticated session.
Since I also needed a master page with logic and markup specific to this application, I created a custom master page that inherits from CanvasIFrameMasterPage. In the markup for the custom master page, it references its code-behind with the CodeBehind attribute:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="IFrameMaster.Master.cs"
Inherits="IFrameSample.IFrameMaster" %>
Within the code-behind, the custom master page is set to inherit from CanvasIFrameMasterPage:
public partial class IFrameMaster : Facebook.Web.CanvasIFrameMasterPage
Since this application requires that users always have an authenticated session, I set the RequireLogin property to true in the master page. This value will then be picked up by every page that uses this master page:
public IFrameMaster()
{
RequireLogin = true;
}
Finally, each page is set to use this custom master page by setting the MasterPageFile attribute in the Page directive as well as creating a MasterType directive. The easiest way to set up the content pages is to create them through the master page: just right-click on the master page in Solution Explorer and select "Add Content Page". The new page will have the correct MasterPageFile attribute set as well as each of the <asp:Content> elements used by the master page, although you will have to set the MasterType directive manually:
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/IFrameMaster.Master"
CodeBehind="Default.aspx.cs" Inherits="IFrameSample.Default" %>
<%@ MasterType VirtualPath="~/IFrameMaster.Master" %>
There are times when you might not want to use that Masterpage. For those times, we have added a logincontrol called FBMLCanvasLoginControl. This control needs to be included on each of your FBML canvas pages and it will handle the authentication handshake.
<Facebook:CanvasIFrameLoginControl runat="server" ID="login" RequireLogin="true"/>
If you use the login control, you will need to use it to access the API in your code-behind.
ASP.NET MVC Support
The supported approach for writing FBML canvas applications using ASP.NET MVC involves two facets.
- Add an attribute for controller actions to handle authentication.
- Use an extension method to the controller to get an instance of the API object to make calls to Facebook.
[HandleError]
public class HomeController : Controller
{
private const string APIKEY = "yourkey";
private const string SECRET = "yoursecret";
[FacebookAuthorization(IsFbml = false, ApiKey = APIKEY, Secret = SECRET)]
public ActionResult Index()
{
Api api = this.GetApi(APIKEY, SECRET);
var user = api.Users.GetLoggedInUser();
return Content("Hello, " + user.ToString());
}
public ActionResult About()
{
return View();
}
}
When using this attribute, you do not need to include the apiKey and secret (in either the attribute or GetApi call) if these are specified in your web.config. In the above code, you will see the Authorization attribute added to the Action method and then a call to the extension method GetApi to get the Instance of the Facebook.Rest.Api object that you need to make any of the necessary rest calls.
Making REST Calls to the API
If you're using the CanvasIFrameMasterPage, making calls to the Facebook API over its REST-like interface is a snap. The master page has an Api property, and all of the API calls can be made through the child objects of that object. Each of the methods is structured as close to the actual Facebook method as possible, while still being strongly-typed and following typical .NET conventions. For example, here's the code I used to send e-mails through the notifications.sendEmail API method:
var subject = "Thank you for telling us your favorite color";
var body = "Thank you for telling us what your favorite color is. We hope you have enjoyed using
this application. Encourage your friends to tell us their favorite color as well!";
this.Master.Api.Notifications.SendEmail(this.Master.Api.Session.UserId.ToString(), subject, body, string.Empty);
Each of the other methods are similar. The return values are also strongly-typed values, based on the schema from Facebook. For example, if you wanted to find out the name of a user with a certain ID, you might use code like this:
user someUser = this.Master.Api.Users.GetInfo(userId);
string name = someUser.name;
Each of the CanvasBasePage/CanvasMasterPage classes works similarly, so that making calls to the Facebook API is as easy as possible.
XFBML and Cross-Domain Communication
XFBML is a method for using FBML (Facebook Markup Language) on IFrame pages. FBML itself is an extension of HTML to allow developers to more tightly integrate their applications with Facebook. Using FBML, developers can use Facebook components such as the profile and news feed in their own applications.
In an FBML canvas application, no special setup is required to use FBML, since Facebook processes the markup before sending the HTML back to the client. However, in an IFrame application, the markup from the application is sent directly to the client without passing through Facebook's servers, so some setup is required.
In this sample, most of the setup is done in the master page (in fact, that's the main reason we have a custom master page at all). First, the page needs to start with an XHTML DOCTYPE declaration, and the <html> tag has to include an xmlns:fb attribute so that it works in IE:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:fb="http://www.facebook.com/2008/fbml">
There are two pieces of JavaScript that are needed on the master page, within the <body> tag. One comes before the XFBML content:
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
And the other must come after:
<script type="text/javascript">
FB_RequireFeatures(["XFBML"], function() {
FB.Facebook.init("c1aefc3e1eb232d9e8ca1e25ea583b69", "channel/xd_receiver.htm");
});
</script>
The two parameters in the above call to FB.Facebook.init must be customized to your application. The first is your API key, which you would normally want to obtain from the web.config, but is stored directly in the JavaScript here for readability purposes. The second is what's known as a "cross-domain communication channel file". This file is what allows your application to communicate with Facebook to process the FBML tags. The file itself is named xd_receiver.htm, and is always the same across all of your applications. It looks like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html >
<head>
<title>Cross-Domain Receiver Page</title>
</head>
<body>
<script src="http://static.ak.facebook.com/js/api_lib/v0.4/XdCommReceiver.js?2" type="text/javascript"></script>
</body>
</html>
The important part is the location of this file. This file needs to be located somewhere on your site, and you must pass a relative path to it in the call to FB.Facebook.init. A relative path means that the path cannot start with "/" and just use the path from the root of your Web application. It must use a path relative to the current page. In this sample, the file is located in the channel folder, which is at the same level as the Web pages. For more information on how to place this file, see the wiki page on the cross-domain communication channel listed at the end of this guide.
Finally, make sure you have the Connect URL for your application correctly set to your canvas URL in the application settings on Facebook (you should have set this up when you first created the application).
Once this setup is complete, you can start using XFBML tags on your pages. For example, here is a tag to get a user's first name. Note that all XFBML tags require a closing tag, even in cases like this where you would normally end the opening tag with "/>":
<fb:name firstnameonly="true" useyou="false" linked="false" uid="loggedinuser"></fb:name>
FBML Server Controls
In order to simplify the ASP.NET programming experience of building an FBML application. We have supplied a set of Server Controls that support the entire FBML namespace. These controls can be used in a manner similar to typical ASP.NET server controls and will render FBML as specified on the Facebook wiki. This will provide a fully supported server programming model for FBML. These controls are not yet supported in the ASPX design surface, but they will be in the toolbox and will provide full IntelliSense support in the Source view of an ASPX page. The code listing below provides a glimpse at how a few of these controls can be placed on an FBML page. Each of these controls supports rendering XFBML compliant text (for any that are supported in XFBML)
<%@ Register Assembly="Facebook.Web" Namespace="Facebook.Web.FbmlControls" TagPrefix="fb"
%>
<fb:Fbml ID="Fbml1" runat="server">
<ContentTemplate>
<fb:IfSectionNotAdded ID="IfSectionNotAdded1" runat="server" Section="Profile">
<ContentTemplate>
Display our box on your profile!<br />
<fb:AddSectionButton ID="AddSectionButton" runat="server" Section="Profile"></fb:AddSectionButton>
</ContentTemplate>
</fb:IfSectionNotAdded>
<fb:Name ID="Name1" runat="server" Uid="loggedinuser"></fb:Name>
<fb:Board ID="Board" runat="server" Xid="aaaa" Title="TTT"></fb:Board>
<fb:Title ID="Title" runat="server" Text="T3"></fb:Title>
<fb:Dialog ID="Dialog" runat="server" Identifier="Dialog">
<ContentTemplate>
<fb:DialogTitle ID="dialogtitle" runat="server" Text="Title of Dialog"></fb:DialogTitle>
<fb:DialogContent ID="content" runat="server">
<ContentTemplate>this is the content of the dialog</ContentTemplate>
</fb:DialogContent>
</ContentTemplate>
</fb:Dialog>
<fb:Wall ID="wall" runat="server">
<ContentTemplate>
<fb:WallPost ID="wallpost" runat="server" Uid="1">
<ContentTemplate>
this is some stuff<br />
<fb:WallPostAction runat="server" ID="WallPostAction" Href="http://localhost" Text="the text for the link"></fb:WallPostAction>
</ContentTemplate>
</fb:WallPost>
</ContentTemplate>
</fb:Wall>
</ContentTemplate>
</fb:Fbml>
Feed Form
The feed form is a method for you to post stories and other information about what users have been doing on your application onto the Feed system. Once a story has been posted to a user's feed, all of their friends can see it, making the feed a great method for users to tell their friends what they've been up to, as well as for you to tell more users about your application.
To use the feed form, you first have to have a template bundle set up (which was done during the application setup). Then you just need to make a JavaScript call to FB.Connect.showFeedDialog with the correct parameters, including the data to fill the template with. This will pop up a dialog box displaying the story, and asking the user if they would like to publish the story or not:
var templateData = new Object();
templateData.color = color;
FB.Connect.showFeedDialog("101489467051", templateData, null, "", null, FB.RequireConnect.require, feedSent);
.jpg)
More information about how to set up the template data can be found on the Facebook Developers wiki.
If you need to do something after the feed is sent, you can send a callback parameter, which was the feedSent variable in the snippet above. Once the feed dialog is closed, the callback function will be called. In this sample, the form is submitted so that we can send an e-mail to the user:
function feedSent() {
submitForm(); // this function dynamically generated by Page_Load method
}
Extended Permissions
In order to perform certain actions on the Facebook Platform (such as sending e-mails and publishing items to a user's stream), your application has to ask the user for special permissions. Facebook calls these "extended permissions".
There are several ways to ask users for these extended permissions. In this sample, we used the <fb:prompt-permission> tag. This tag allows you to turn a piece of text into a link that, when clicked, will pop up a dialog to let the user grant your application a specific permission:
<p>If you would like this application to send you e-mail messages, please <fb:prompt-permission perms="email">click here</fb:prompt-permission>.</p>
.jpg)
You can also use the users.hasAppPermission API call to check if the user has a specific permission before you attempt an action that requires that permission:
if (Master.Api.Users.HasAppPermission(Enums.ExtendedPermissions.email))
{
SendThankYouEmail();
}
In addition, the FBMLBasePage, MasterPage, login control, and MVC attribute all support a property that allows you to set the permissions required by your application. If you use this property, the authentication process with Facebook will include a check for the required permissions and will redirect the user to a page requesting those permissions prior to displaying your canvas application.
For example, if you are using the FBMLMasterpage you can add a constructor to your master page where you specify the permissions as follows:
public partial class IFrameMaster : Facebook.Web.CanvasIFrameMasterPage
{
protected string selected = string.Empty;
public FBMLMaster() : base()
{
this.RequiredPermissions = new List<Enums.ExtendedPermissions>() {
Enums.ExtendedPermissions.publish_stream };
}
Alternatively, if you are using the login control, the syntax would be:
<%@ Register TagPrefix="Facebook" Namespace="Facebook.Web" Assembly="Facebook.Web" %>
<Facebook:CanvasIFrameLoginControl runat="server" ID="login" RequireLogin="true"
RequiredPermissions="offline_access,publish_stream"/>
Lastly, if you are using the MVC action attribute, the model is similar to the LoginControl.
[FacebookAuthorization(IsFbml = false, ApiKey = APIKEY, Secret = SECRET,
RequiredPermissions="publish_stream,offline_access")]