I'm not really going to go into much detail about the client - it's fairly standard "modern" HTML and JavaScript about which you can find much better information that I could cover here. One reason why I can't say a lot about it is that pretty much all of it was done by my colleague Mike Armstrong and not me! I'll just point out some things to watch out for...

First, adding the the Facebook C# SDK ASP.NET MVC NuGet installation process creates and wires up a FacebookInit.cshtml file which, as you might guess, looks after logging into Facebook for your application. Typically, your application loads without the user being logged in; the user logs in; and the page reloads with an authenticated user - FacebookInit.cshtml includes a reload on authentication to facilitate just this. Because our application is a Facebook canvas application, the user is already logged in by the time our app loads, so there's no need for this reload, so we removed the auth.statusChange handler.

Er, that was probably the only real gotcha in the project!

In terms of communication with the servers, Facebook operations are fairly well documented in the Facebook JavaScript SDK documentation. We aimed to use the Graph API for most queries, but that doesn't yet support everything we wanted to do. An example of a graph API call is getting the opponent's name:

FB.api("/" + userId + "?fields=name", function (response) { ... });

And an example of using the legacy FQL is determining if the friend someone has chosen to challenge is registered with the game:

FB.api({
          method: 'fql.query',
          query: 'SELECT is_app_user FROM user WHERE uid=' + userId
          }, function (installedResponse) { ... });

Communication with our server used the jQuery Ajax functions, for example:

var address = serviceUrl + 'MakeMove?gameId=' + gameId + '&playerId=' + playerId + '&allocationString=' + allocations;

var timesTried = 0, maxTries = 3;
var trier = function () {
timesTried++;
$.ajax({
url: address,
contentType: 'application/json',
dataType: 'json',
success: function (response) {
...
},
error: function (response) {
if (timesTried < maxTries) {
trier();
} else {
... handle error ...
}
}
});
}
trier();

Because communication failures can occur, we fudge things a bit by trying the message a few times before giving up - bit of a hack, and maybe not really necessary... On failure (i.e., when the error handler executes), we increment the tries counter and give it another go unless a limit has been exceeded.

That's all I'm going to say about the client - and that pretty much concludes the quick walkthrough of our game.