In part 1 of this post , I showed how to create a SQL database in Windows Azure, create a schema for adding leaderboard functionality to a game, create an Entity Framework model for the database, and then create and test a WCF Data Service on top of the model that provides a rich REST-style interaction model with great query support via OData. If you have not yet read part 1, you should do so before continuing.

And if you want to follow along, but don't yet have a Windows Azure account, you you can sign up for a 90-day trial that will give you everything you need.

If you'd like some back story on the games I'm planning to use to demonstrate the leaderboard service, check out this post.

In this second part, I'll show you:

How I deploy the OData service to Windows Azure

How I wire up my Windows 8 JavaScript games, Space Cadet and Catapult Wars, to the leaderboard service.

Deploying the Service

Now, I could start integrating the service into our games using the local version of the service, but since the service is pretty simple and I'm confident that it'll do what I want, let's go ahead and publish the service to Windows Azure, and use the published URI for the client app.

If you've never published a cloud service to Windows Azure, or it's been a while since you've used the Visual Studio tools for Azure, you'll be pleasantly surprised by how easy it is. All that's required is a one-time setup of the publishing credentials, which I'll start by right-clicking my Cloud project and selecting Publish…

Wiring up the Leaderboard Client App

One goal I have for this series of blog posts, and the accompanying data, is to make the leaderboard code as minimally intrusive to the basic game logic as possible. To that end, I'm planning to define all of the leaderboard logic in a single JavaScript file, with the functionality exposed to the client game using the WinJS namespace functionality, as in the following code example:

This allows me to expose a consistent API for leaderboard functionality, accessible by using the namespace Leaderboard, followed by the desired API member. So to initialize the leaderboard, I would call Leaderboard.init(args). A big advantage here is that the game itself doesn't have to know anything about the underlying implementation of the leaderboard logic, and it's pretty straightforward for me to change the internal logic of each of the functions to use a different back-end service without changing the code in the game itself (which is precisely what I'll be doing in future posts on using ASP.NET Web API and Windows Azure Mobile Services to provide similar back-end services).

Another neat thing is that once I've referenced the JavaScript file in the game's main HTML file (for example, in Dave Isbitski's Space Cadet, this would be default.html), Visual Studio will automatically provide IntelliSense statement completion for my API, including the arguments required by a given function, as shown below:

Additionally, the IntelliSense lookup displays a comment which appears on the line prior to the function for that API as the description for the function. Makes it very convenient to add some simple documentation for your API.

As you can see from the code listing above, the API supports two basic types of score tracking…high score and win/loss/tie record. For the latter, we have functions to add a win, loss, or tie to the existing record, and for high score, we have a function to update the player's score (assuming it's higher than the existing high score for that player). Then, since we might want to display the current leaderboard information, we have a couple of functions that return the list of high scores, or the Win/Loss/Tie records for the current game. Both of these functions update an internal variable named leaderboardList, which is exposed as an API member with the same name.

Initializing the Leaderboard

I'll start by declaring most of my variables up-top. Since JavaScript uses something called hoisting, which treats variable declarations anywhere within a given scope as if they were declared at the top of the function…BUT if the line where the variable is declared also includes initialization, the initialization is not hoisted, which can result in some tricky situations to debug. It's a good practice to declare all variables at the top of the function scope in which they're used:

Next comes the init function, which the game provides with the game and player names, and which checks to ensure that at least one score record exists and if not, intializes the leaderboard with a blank score record for that player/game combo. Note that in the interest of simplicity, I have not added any code to ensure that the game/player combo is unique across all possible clients of the leaderboard service.

In this function, I'm showing a slight variation on the promise pattern. This time, I declare a variable called scorePromise that is passed the result of calling getCurrentPlayerScore. In line 3, I then call .done, passing in the function I want called as usual. This code just makes what's happening (getCurrentPlayerScore returns a Promise object) a little more explicit, and may aid readability of my code. In line 4 above, I check to see if the new score passed into the function is higher than the score returned by getCurrentPlayerScore via the promise object, and if so, call updateScoreRecord, passing it the currentScore object.

NOTE: In the code above, you might notice that I'm checking "Score1", when you might expect from the schema I showed in part 1 of this post, which had a column named "Score," that the property should be "Score". Well, this happened because of the way that I named the table ("Scores") and column ("Score"), and the fact that in the process of building the Entity Framework model, the default is to singularize the entity names, so the entity in the model representing the Scores table is called "Score". Because you can't have an entity with a property name that is the same as the entity name, Entity Framework helpfully renamed the property "Score1" and WCF Data Services provides the same property on the Score object.

This function takes the score record passed in from updateHighScore, prepares it for submitting using JSON.stringify, and then make the result the data property of the xhrOptions object. I also pass in a Content-type header to specify that I'm sending JSON data, as well as the X-HTTP-Method header with the value of "MERGE". This tells the OData service to update the specified record with any properties provided, while leaving any unspecified values unchanged. You can read more about updating records via OData here.

Updating the high score from the game code is fairly straightforward, requiring only passing in the score to update:

Leaderboard.updateScore(score);

That's all that's needed to wire up the functionality to store and update score records for a given game (in this case, Space Cadet). For Space Cadet, and similar games that allow the player to change their player name, I also added a function to update the player name, and there are functions to increment the Wins, Losses, and Ties properties for games that keep score using those values instead of a numeric high score. And for Catapult Wars, I can use the exact same JavaScript library. The only change needed is to call Leaderboard.addWin or Leaderboard.addLoss, depending on whether the player wins or loses the game.

Adding the Leaderboard Page

Of course, having all this leaderboard info doesn't do me a lot of good if I don't show it off every now and then, so to remedy that, I added a folder to my project called Leaderboard, and added to it a new Page control (which adds a matched set of HTML, CSS, and JavaScript files) called Leaderboard.html. Here's what the markup looks like for Space Cadet:

It simply sets up a WinJS.UI.ListView control that I'll use for databinding the score results from the service, with a template that displays each player name along with their score. There's also a back button to return the player to the game once they're done looking at the leaderboard.

Note that for Space Cadet, I'm leveraging the roaming settings support in Windows 8, which means that wherever I have the game installed, my player name will follow me, as long as I'm logged in with the same Microsoft Account. In the ready function, I first bind the click event of the back button to the goBack function, which simply reloads default.html. Next, I call Leaderboard.init (to ensure the leaderboard has been properly initialized for the game), and then call Leaderboard.getTopTenScores, and provide a function to be called when this operation is complete. In that function, I set the title of the leaderboard page to the name of the game plus "Top 10", and finally set the itemDataSource of the ListView control to the dataSource property of the WinJS.Binding.List passed in to the function from getTopTenScores. Add a little CSS for formatting, and here's the result:

Nothing fancy, I'll admit, but it gets the job done. Here's the code for the getTopTenScores function:

A couple of things to note are the use of the $orderby and $top query parameters, which help organize the data in the way I need it for the leaderboard (you might also notice that I don't have a full 10 records in my database yet, but if I had more than 10 records, this query would only return the top 10), and that I'm not using the player name in the query this time, since I actually want to get scores for all players for this game.

Again, I'm returning a WinJS.Promise object, and if the xhr operation is successful, I create a new WinJS.Binding.List object based on the scores retrieved, and pass it to the completed function, which allows the Leaderboard.html page to bind it to the ListView control on the page. The leaderboard page for Catapult Wars looks almost identical, but in this case, I'm calling Leaderboard.getTopTenWins, and binding the Wins property in the ListView:

Wrap-up

So in this pair of posts, you've seen how I created a new SQL database in Windows Azure, defined a schema for the data, used Entity Framework to create a model of the data, and wrapped that in a WCF Data Service, providing a powerful, but simple URL-based query syntax that I can use to interact with my service. You've also seen how I created a single JavaScript library that used the WinJS namespace functionality to expose a simple API that can be used by multiple games to interact with the leaderboard service.

As noted in the overview post for this series, there are both advantages and disadvantages to this approach to building back-end services:

Advantages
Mature platform – SQL Server, Entity Framework, and WCF Data Services have each been around for numerous versions, and have had time to improve and grow over that time. Maturity also means greater familiarity for .NET developers.
Data format options – can return data in XML (ATOM) or JSON format.
Customizable – implementing custom logic can be done in a variety of ways, including attributes, custom code in the WCF data service, and exposing stored procedures as Service Operations.
Query flexibility – thanks to OData's powerful query syntax, requesting and submitting data is easily accomplished by building the appropriate URL and making simple HTTP requests.

Disadvantages
Complexity – as you might have noticed from the length of this blog post, there are quite a few steps to getting this set up, and a number of layers. While this means more points at which the service may be customized, it also increases the overall complexity of the solution.
No client library for JavaScript apps – while there is direct support in XAML-based Windows Store apps for working with OData services, there is no official support for OData services in JavaScript apps. As you have seen, it's pretty easy to build xhr requests that access the service, but this approach may seem rather foreign to anyone who's used an OData client library, many of which use LINQ-style syntax for performing operations on the service, treating the service more like a local object, and which hide the underlying HTTP complexities from the developer.

So is this the right approach for your app? The answer, of course, is "it depends." You can certainly build a robust, scalable, and easy-to-use service back-end for your Windows Store app or game using the techniques I've illustrated here. But there are other, simpler approaches that you may want to consider as well.

What's Next?

In the next part of this series, I'll show another approach to building back-end services, as I take on building this same game leaderboard service using the new ASP.NET Web API.

While you're waiting, consider signing up for Generation App. There are lots of great resources available for building Windows 8 apps (and now for Windows Phone 8 as well). It's free, and you control how often updates are sent, so there's no good reason to pass it up. Sign up now!