Adding Facebook Like buttons and using the Graph API with ASP.NET MVC

Social features have become very popular with site owners. It is almost hard to imagine a popular site without them. Well-implemented social features bring extra users to your site, incentivized by their friends and therefore more likely to interact and convert.

The disadvantage of social features is that they result in extra scripts being loaded and executed on all your pages, which makes them slower, especially on mobile. Using services like AddThis you can add lots of social buttons on your site with little effort, but you need to carefully weigh the benefits against costs of each service you offer. Every service you implement loads another javascript file that executes in the context of your site, and that sends information about your visitors back to the service, so there is also a privacy cost to your visitors.

In my view, you should just implement just a few social networks that really add value, and that are actually used. And you might consider offering users a choice, by explicitly asking if they accept tracking cookies in return for the social features, and leave those social buttons out completely if they decline. This explicit cookie consent is even mandatory in Europe and especially in the Netherlands, were I live.

Although there are many social networks, in most countries Facebook is by far the largest and most important network. Facebook is relatively open and easy to integrate with. For our Cloud Auction website, we wanted to integrate with Facebook in several ways:

  • Use Facebook as a login provider, so that users can use their Facebook login an do not have to store or remember yet another password
  • Use Facebook Like buttons for the site and for individual products
  • Use the Facebook Graph API to create a custom action, to share a successful purchase on the auction
  • Use our whole website as a Facebook “Canvas App” or “Facebook Tab”.

I already described how to implement Facebook Login in my post on Authentication with SimpleMembership. Reusing the site as a Canvas app will take another post in the future. This post will describe how to integrate with the Facebook Graph API on a normal site, built with ASP.NET MVC.


FACEBOOK APP REGISTRATION

All types of Facebook integration start with registration of your site or app, and getting a Facebook. In my post on Authentication with SimpleMembership, I already described how register a site with Facebook. In short: 

My App Settings in Facebook now look like this:

Add facebook buttons



LIKE BUTTON

The easiest way to get a Facebook button on your site is by using the Facebook SDK for JavaScript. To get this initialized, we will have to add a few things to our ASP.NET MVC site.

1. The first part is a html element:

<div id="fb-root"></div>

The Facebook SDK for Javascript uses this div element to insert other elements, and it expects this div to be near the top of the page. So, we will place it near the top of the page, just after the fixed position menu bar in _Layout.cshtml, so that it is available on every page.

2. The second part is the “Channel File”. This is used to “greatly improves the performance of the JS SDK by addressing issues with cross-domain communication in certain browsers”. I do not fully understand how this works, so I’ll do as Facebook instructs: the Channel File is a page with very long cache expiration time (one year) that does nothing but reference the Facebook Javascript file. I implemented it with a View that includes the Facebook JavaScript using the configured culture of our site:


@{
Layout = null;
}
<html>
<body>
<script type="text/javascript" src="//connect.facebook.net/@(System.Globalization.CultureInfo.CurrentCulture.ToString().Replace("-", "_"))/all.js"></script>
</body>
</html>
view rawFacebookChannel.cshtml hosted with ❤ by GitHub


The Cache Expiration is configured on the Controller Action Method:


using Auction.Web.Utility;
using System.Web.Mvc;

namespace Auction.Web.Controllers
{
[AllowAnonymous]
public class SiteController : BaseController
{
//
// GET: /Site/
public ActionResult Index()
{
return View();
}

public ActionResult AllowCookies(string ReturnUrl)
{
CookieConsent.SetCookieConsent(Response, true);
return RedirectToLocal(ReturnUrl);
}

public ActionResult NoCookies(string ReturnUrl)
{
CookieConsent.SetCookieConsent(Response, false);
// if we got an ajax submit, just return 200 OK, else redirect back
if (Request.IsAjaxRequest())
return new HttpStatusCodeResult(System.Net.HttpStatusCode.OK);
else
return RedirectToLocal(ReturnUrl);
}


[OutputCache(Duration = 60 * 60 * 24 * 365, Location = System.Web.UI.OutputCacheLocation.Any)]
public ActionResult FacebookChannel()
{
return View();
}
}
}
view rawSiteController.cs hosted with ❤ by GitHub


3. The third part is including the actual script on the page. Because we will probably want to use the like button on many pages, we will load this script in _Layout.cshtml, right before the scripts section.


<script>
window.fbAsyncInit = function () {
FB.init({
appId: "@System.Configuration.ConfigurationManager.AppSettings["FacebookAppId"]", // App ID
channelUrl: "//@(Request.Url.Authority + Url.Content("~/Site/FacebookChannel"))", // Channel File
status: true, // check login status
cookie: false, // do not rely on cookies to maintain the session
xfbml: true // parse XFBML
});
};

// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/@(System.Globalization.CultureInfo.CurrentCulture.ToString().Replace("-", "_"))/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
view raw_FacebookInit.cshtml hosted with ❤ by GitHub



@using Auction.Web.Utility
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>@ViewBag.Title - My ASP.NET MVC Application</title>
@RenderSection("meta", required: false)
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link href="~/Content/less/bootstrap.less" rel="stylesheet">
<style type="text/css" >
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<link href="~/Content/less/responsive.less" rel="stylesheet">

@Html.Partial("_html5shiv")

<!-- Fav and touch icons -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="~/Content/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="~/Content/ico/apple-touch-icon-114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="~/Content/ico/apple-touch-icon-72-precomposed.png">
<link rel="apple-touch-icon-precomposed" href="~/Content/ico/apple-touch-icon-57-precomposed.png">
<link href="~/Content/ico/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
@Html.Partial("_NavBar")
<div id="fb-root"></div>
<div class="container">
@if (CookieConsent.AskCookieConsent(ViewContext))
{
@Html.Partial("_CookieConsentMessage")
}
@RenderSection("featured", required: false)
@RenderBody()
<hr />
<div class="footer">
<p>&copy; Company 2013</p>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")

@if (CookieConsent.HasCookieConsent(ViewContext))
{
@Html.Partial("_FacebookInit")
}

@RenderSection("scripts", required: false)
</div>
</body>
</html>
view raw_Layout.cshtml hosted with ❤ by GitHub


4 Then, finally, we can add that Like button on the page. We’ll also add the Facebook Send button.


@using Auction.Web.Utility
@{
ViewBag.Title = "SignalR Auction";
ViewBag.Description = "reference implementation of a modern website";
}

@section meta {
<meta name="description" content="@ViewBag.Description">
<meta property="og:title" content="@ViewBag.Title" />
<meta property="og:description" content="@ViewBag.Description" />
<meta property="og:type" content="website" />
<meta property="og:image" content="@Url.Content("~/Content/images/auction.jpg")" />
<meta property="og:site_name" content="Cloud Auction Demo" />
<meta property="fb:admins" content="@System.Configuration.ConfigurationManager.AppSettings["FacebookAdmins"] />
<meta property="og:url" content="@Request.Url" />
<link rel="canonical" href="@Url.Action("Index", "Auction", new RouteValueDictionary(new { area = "" }), Uri.UriSchemeHttps, Request.Url.Host)" />
}
<div class="row-fluid"">
<div class="page-header">
<h1>
<strong data-bind="text: Title"></strong>
<small data-bind="text: Info"></small>
</h1>
</div>
</div>
<div class="row-fluid">
<div class="span4">
<div class="carousel slide">
<!-- Carousel items -->
<div class="carousel-inner" data-bind="foreach: Photos">
<div class="item" data-bind="css: { active: $index() == 0 }"><img src="/Content/images/none.png" data-bind='attr: { src: $data }' /></div>
</div>
<!-- Carousel nav -->
<a data-bind="visible: Photos().length > 1" class="carousel-control left" href="#photos" data-slide="prev">&lsaquo;</a>
<a data-bind="visible: Photos().length > 1" class="carousel-control right" href="#photos" data-slide="next">&rsaquo;</a>
</div>
</div>
<div class="span8">
<div data-bind="html: Details"></div>
<h2 data-bind="text: CurrentPrice"></h2>
<p><span data-bind="text: TimeRemainingText"></span> remaining</p>
@if (CookieConsent.HasCookieConsent(ViewContext))
{
<div class="fb-like" data-href="@Request.Url.GetLeftPart(UriPartial.Path)" data-send="true" data-layout="button_count" data-width="350" data-show-faces="false" data-font="lucida grande"></div>
}
</div>
</div>

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/ko-signalr")
<script type="text/javascript" src="~/signalr/hubs"></script>
@Scripts.Render("~/bundles/home/auction")
}
view rawIndex.cshtml hosted with ❤ by GitHub


With that, we now have a like button, if we click it, it will publish the Like action to the users timeline, and the user can also add a personal message for friends to read.

Add Facebook buttons

 

Add Facebook buttons

 

 


OPEN GRAPH META TAGS
Now we have created a nice Like button, but when you test it, you will find that it only seems to work, but it doesn’t work really: the Like will not appear on our timeline. That’s because our development environment is not accessible from the internet, and Facebook will not accept a Like for a site that it can’t access. So, to test it, you’ll have to deploy the site to an externally accessible webserver, i.e. as an Azure Website. After you do that, you will find that it really works.

But the Like action that is published still does not look as good as the Likes you have seen linking to other sites. To influence how the Like looks inside the Facebook environment, you will have to add some Open Graph Meta Tags to the page. What happens after someone likes a page is that Facebook will come in and fetch that page to get the information it needs to show the story on the users’ timeline. Facebook stores metadata about pages and other objects in a database. The Facebook database is not a SQL database, it is a Graph database, linking objects (such as our webpage) with users and actions (the user liking that page). The properties that Facebook will store about our page is provided using Open Graph Meta Tags. These are meta tags that are an extension of the well known description and keyword tags that search engines use for indexing the page.


@using Auction.Web.Utility
@{
ViewBag.Title = "SignalR Auction";
ViewBag.Description = "reference implementation of a modern website";
}

@section meta {
<meta name="description" content="@ViewBag.Description">
<meta property="og:title" content="@ViewBag.Title" />
<meta property="og:description" content="@ViewBag.Description" />
<meta property="og:type" content="website" />
<meta property="og:image" content="@Url.Content("~/Content/images/auction.jpg")" />
<meta property="og:site_name" content="Cloud Auction Demo" />
<meta property="fb:admins" content="@System.Configuration.ConfigurationManager.AppSettings["FacebookAdmins"] />
<meta property="og:url" content="@Request.Url" />
<link rel="canonical" href="@Url.Action("Index", "Auction", new RouteValueDictionary(new { area = "" }), Uri.UriSchemeHttps, Request.Url.Host)" />
}
<div class="row-fluid"">
<div class="page-header">
<h1>
<strong data-bind="text: Title"></strong>
<small data-bind="text: Info"></small>
</h1>
</div>
</div>
<div class="row-fluid">
<div class="span4">
<div class="carousel slide">
<!-- Carousel items -->
<div class="carousel-inner" data-bind="foreach: Photos">
<div class="item" data-bind="css: { active: $index() == 0 }"><img src="/Content/images/none.png" data-bind='attr: { src: $data }' /></div>
</div>
<!-- Carousel nav -->
<a data-bind="visible: Photos().length > 1" class="carousel-control left" href="#photos" data-slide="prev">&lsaquo;</a>
<a data-bind="visible: Photos().length > 1" class="carousel-control right" href="#photos" data-slide="next">&rsaquo;</a>
</div>
</div>
<div class="span8">
<div data-bind="html: Details"></div>
<h2 data-bind="text: CurrentPrice"></h2>
<p><span data-bind="text: TimeRemainingText"></span> remaining</p>
@if (CookieConsent.HasCookieConsent(ViewContext))
{
<div class="fb-like" data-href="@Request.Url.GetLeftPart(UriPartial.Path)" data-send="true" data-layout="button_count" data-width="350" data-show-faces="false" data-font="lucida grande"></div>
}
</div>
</div>

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/ko-signalr")
<script type="text/javascript" src="~/signalr/hubs"></script>
@Scripts.Render("~/bundles/home/auction")
}
view rawIndex.cshtml hosted with ❤ by GitHub


With those properties, Facebook can show a much richer story on the timeline: a title, an image, a short description, the app name, a link back to the page. Even the Like-popup loos better:

Add Facebook buttons

 
That like show up in the Facebook timeline with a nice picture, a title, short description, and more links for sharing.

Add Facebook buttons

 
So with that we have that Like button we wanted! But, it turns out, we can still make it better.

CUSTOM ACTIONS USING THE GRAPH API

A user Liking a Webpage is the most common combination of an action (Like) and an object (webpage). The Graph database of Facebook is extensible, meaning that developers can add their own objects and actions. Those can be used to create customized “stories” that can be shared on our users’ timelines. For instance, we can create a custom object “Lot” for our auction, and add custom fields for the price and auction time, like this:

Add Facebook buttons


We can then specify how this object will be shown on the timeline, and what words to use to describe it:

Add Facebook buttons




We can now use those custom graph attributes in our meta section. In the previous example, we would use

<meta property="og:type" content="macawcloudauction:lot" />

to mark a page that shows a lot in our auction. If you now like that lot object, it will looks like this on the timeline:

Add Facebook buttons




Creating custom objects and custom actions can create really nice integration within Facebook. Users can share their stories further, you can “gamify” your business by creating badges and achievements when users do a certain things. Facebook is very open and accessible for an ASP.NET developer, a lot of things are possible. I’m sure you get the picture!

[This post is part of the series Development of a mobile website with apps and social features]

Fabienne van Tol
Recruitment

Werken bij Macaw?