If you’re looking to build a Facebook App using ASP.NET MVC, then you’re in the right place. With the release of ASP.NET and Web Tools 2012.2, we’ve added lots of updates to our Facebook Application template and library since we first introduced it in the Preview.
The library, Microsoft.AspNet.Mvc.Facebook, can be downloaded as an independent NuGet package and it contains everything you need to create a Facebook Canvas application using ASP.NET MVC. It’s already included by default in the Facebook Application template to give you a quick jump start on building a Canvas Page.
Please refer to the tutorial for instructions on how to setup the Facebook Application template. In this post I’ll mainly focus on the design/API changes that we made from the Preview to RC. This will give you a pretty good idea of how the new APIs work in the updated Facebook Application template.
Introducing FacebookContext
Before RC, we used to model bind the User and other Facebook objects as parameters. The problem with model binding these parameters is that we needed to call Facebook Graph API to get the values and the model binders in MVC don’t support async. That’s why in RC, we’re replacing them with a FacebookContext parameter from which you can access the user ID, access token and the parsed signed request. More importantly, the FacebookContext has an instance of the FacebookClient which can be used to make asynchronously calls to Facebook to get the values for the User and other Facebook objects.
The instance of FacebookClient is populated with the required information such as AppId, AppSecret and AccessToken, so it’s ready to use.
public async Task<ActionResult> Index(FacebookContext context)
{
if (ModelState.IsValid)
{
MyAppUser user = await context.Client.GetCurrentUserAsync<MyAppUser>();
return View(user);
}
return View("Error");
}
FacebookClient Extensions
We’ve added a number of extension methods to FacebookClient to make the common tasks, such as getting the current user and his/her friends, simpler.
In fact, most of the extension methods above are based on GetFacebookObjectAsync<TFacebookObject>(string objectPath). If you’re familiar with Facebook C# SDK, you might be wondering how it is different from GetTaskAsync<TResult>(string path). Well, the main difference between them is that GetFacebookObjectAsync<TFacebookObject>(string objectPath) will automatically generate “fields” query parameter when making the request so you get back only the properties you need. It reduces the payload size and sometime this can be quite significant. For example, if you have the following type named “MyUser”.
public class MyUser
{
public string Id { get; set; }
public string Name { get; set; }
public string Birthday { get; set; }
}
GetFacebookObjectAsync<MyUser>(“me”) will get back something like the following.
{
"id": "1234567",
"name": "sample name",
"birthday": "01/01/2000"
}
but GetTaskAsync<MyUser>(“me”) will get back the full payload. The difference can be even bigger when you’re retrieving a list of friends.
{
"id": "1234567",
"name": "sample name",
"first_name": "sample name",
"middle_name": "sample name",
"last_name": "sample name",
"link": "https://www.facebook.com/sample",
"username": "sample",
"birthday": "01/01/2000",
"location":
{
"id": "123456789",
"name": "Redmond, Washington"
},
"quotes": "Very long quotes...................",
"gender": "male",
"email": "sample@sample.com",
"timezone": -4,
"locale": "en_US",
"verified": true,
"updated_time": "2012-10-11T00:25:53+0000"
}
Being able to automatically generate the “fields” query parameter also makes it easier to retrieve connections (Picture, Friends, Likes, etc) as fields. For instance, you can get back the user information and what user Likes (a connection) in a single request by defining the types below. GetFacebookObjectAsync<MyUser> will automatically take care of generating the appropriate “fields” query to include the Likes connection (assuming you have user_likes permission).
public class MyUser
{
public string Id { get; set; }
public string Name { get; set; }
public string Birthday { get; set; }
public FacebookGroupConnection<Like> Likes { get; set; }
}
public class Like
{
public string Name { get; set; }
public string Category { get; set; }
}
Modeling Facebook Objects
Unlike before, where your Facebook user/object types were required to derive from FacebookUser/FacebookObject, now you can use any POCO type as long as it contains public properties with the matching name. We’ll deserialize the Facebook response using Json.NET. For example, the following Facebook response for a user will match the “MyUser” type below.
{
"id": "1234567",
"name": "sample name",
"link": https://www.facebook.com/sample
}
Note that the property derialization is case insensitive.
public class MyUser
{
public string Id { get; set; }
public string Name { get; set; }
public string Link { get; set; }
}
Defining Connections
As noted previously, now you can include connections (Picture, Friends, Likes, etc) as properties using FacebookConnection<T> and FacebookGroupConnection<T>.
public class MyAppUser
{
public string Name { get; set; }
public string Email { get; set; }
public FacebookConnection<FacebookPicture> Picture { get; set; }
public FacebookGroupConnection<MyAppUserFriend> Friends { get; set; }
}
public class FacebookPicture
{
public string Url { get; set; }
}
public class MyAppUserFriend
{
public string Name { get; set; }
public string Link { get; set; }
public FacebookConnection<FacebookPicture> Picture { get; set; }
}
These types will match exactly how Facebook returns the connection data in JSON.
{
"name": "sample name",
"email": "sample@sample.com",
"id": "1234567",
"picture": {
"data": {...}
},
"friends": {
"data": [
{...},
{...},
{...}
]
}
}
Property Attributes
Since we use Json.NET to do the deserialization, you can use JsonProperty/JsonIgnore to rename/exclude a property.
public class MyAppUser
{
[JsonIgnore] // This ignores the property
public string MyProperty { get; set; }
[JsonProperty("picture")] // This renames the property to picture.
public FacebookConnection<FacebookPicture> ProfilePicture { get; set; }
}
In addition you can apply modifiers to the connections using FacebookFieldModifier. For example, you can get the URL to a larger profile picture by adding the modifier “type(large)” to Picture. Go to Facebook Graph API to see the modifiers that are available. When GetFacebookObjectAsync<TFacebookObject> makes the request, these modifiers will be added to the ?field query parameter.
public class MyAppUser
{
[FacebookFieldModifier("type(large)")] // This sets the picture size to large.
public FacebookConnection<FacebookPicture> Picture { get; set; }
}
public class FacebookPicture
{
public string Url { get; set; }
}
Facebook Authorization
FacebookAuthorizeAttribute can be used just like before to ensure that the signed_request parameter (sent by Facebook) is valid before invoking an action. Additionally, you can require a set of permissions to be granted before reaching the action by passing them into the attribute. In case the authorization fails, either because of invalid signed request or missing permissions, the users will be redirected to a Facebook OAuth dialog asking them to login or grant the required permissions.
Note that FacebookAuthorizeAttribute is not an authorization filter anymore, the actual authorization is done by FacebookAuthorizeFilter. That’s why it’s important to register the FacebookAuthorizeFilter globally to enable this functionality.
public static class FacebookConfig
{
public static void Register(FacebookConfiguration configuration)
{
// Other settings removed for clarity...
// Adding the authorization filter to check for Facebook signed requests and permissions
GlobalFilters.Filters.Add(new FacebookAuthorizeFilter(configuration));
}
}
Having a global authorization filter allowed us to combine the permissions declared on both the controller and the action. Which means the user will see the OAuth dialog once instead twice for the “Profile” action below when the permissions are missing.
[FacebookAuthorize("email")]
public class UserController : Controller
{
[FacebookAuthorize("user_photos")]
public async Task<ActionResult> Profile(FacebookContext context)
{
// Implementation removed for clarity
}
}
AuthorizationRedirectPath
When the permissions are missing, now you have the option of showing an “info” page before redirecting user to the OAuth dialog. In that page you can explaining why your app requires certain permissions so that users are more likely to grant them. To do that, add the following to your web.config and the user will be redirected to Home/Permissions when the authorization fails due to missing permissions.
<appSettings>
<add key="Facebook:AuthorizationRedirectPath" value="Home/Permissions" />
</appSettings>
On the action that is receiving the redirect, you can use FacebookRedirectContext parameter to access information like the required permissions and the RedirectUrl to the Facebook OAuth dialog.
public class HomeController : Controller
{
// Other actions removed for clarity...
// This action will handle the redirects from FacebookAuthorizeFilter when
// the app doesn't have all the required permissions specified in the FacebookAuthorizeAttribute.
// The path to this action is defined under appSettings (in Web.config) with the key 'Facebook:AuthorizationRedirectPath'.
public ActionResult Permissions(FacebookRedirectContext context)
{
if (ModelState.IsValid)
{
return View(context);
}
return View("Error");
}
}
@using Microsoft.AspNet.Mvc.Facebook
@model FacebookRedirectContext
@if (Model.RequiredPermissions.Length > 0)
{
<h3>You need to grant the following permission(s) on Facebook to view this page:</h3>
<ul>
@foreach (var permission in Model.RequiredPermissions)
{
<li>@permission</li>
}
</ul>
<a class="buttonLink" href="@Html.Raw(Model.RedirectUrl)" target="_top">Authorize this application</a>
}
Facebook Realtime Update Support
Out of the box, we provide you with an abstract FacebookRealtimeUpdateController, which is a Web API controller that will handle all the HTTP requests sent by Facebook Realtime Update service. It will take care of verifying the subscription and validating the integrity of the payload by checking the X-Hub-Signature HTTP header. All you need to provide is a verify token and your business logic to handle the update. Here is a sample implementation of FacebookRealtimeUpdateController.
public class UserRealtimeUpdateController : FacebookRealtimeUpdateController
{
private readonly static string UserVerifyToken = ConfigurationManager.AppSettings["Facebook:VerifyToken:User"];
public override string VerifyToken
{
get
{
return UserVerifyToken;
}
}
public override Task HandleUpdateAsync(ChangeNotification notification)
{
if (notification.Object == "user")
{
foreach (var entry in notification.Entry)
{
// Your logic to handle the update here
}
}
}
}
Note that you can have multiple custom FacebookRealtimeUpdateController to handle different subscriptions (Users, Permissions, etc) with different verify tokens.
FacebookConfiguration
The static FacebookSettings class has been replaced by FacebookConfiguration. Notice that many components such as FacebookAuthorizeFilter are taking an instance of FacebookConfiguration in the constructor which makes unit testing easier. For global access to FacebookConfiguration within the application, you can use GlobalFacebookConfiguration.Configuration, which is a singleton instance.
LoadFromAppSettings
This method loads the following properties from appSettings.
- AppId – this property is required.
- AppSecret – this property is required.
- AppNamespace – this property is required if you provided a namespace to the app you created on https://developers.facebook.com/apps.
- AppUrl – this property is optional. By default it’s set to https://apps.facebook.com/{AppId} or https://apps.facebook.com/{AppNamespace} when the AppNamespace is set. The only time you might want to set this is if Facebook changes their app URL structure.
- AuthorizationRedirectPath – this property is optional. See the AuthorizationRedirectPath section above for more information.
<appSettings>
<add key="Facebook:AppId" value="" />
<add key="Facebook:AppSecret" value="" />
<add key="Facebook:AppNamespace" value="" />
<add key="Facebook:AppUrl" value="" />
<add key="Facebook:AuthorizationRedirectPath" value="" />
</appSettings>
ClientProvider property
You can set this property to customize how the FacebookClient is created. GlobalFacebookConfiguration.Configuration uses an instance of DefaultFacebookClientProvider which creates clients that use Json.NET serializers.
PermissionService property
You can set this property to change how current user permissions are retrieved. GlobalFacebookConfiguration.Configuration uses an instance of DefaultFacebookPermissionService which calls into Facebook Graph API to retrieve the current user permissions.
Well, that concludes our overview of the new APIs in the Facebook Application library. I would encourage you to install the ASP.NET and Web Tools 2012.2 and start playing with the Facebook Application template. Please do send us your feedback and feel free to use our CodePlex site to report any issues you might find.
Have fun building Facebook Apps with ASP.NET MVC!
Yao
0 comments