This is Part 2 in a series covering how the Xbox Gamercard application was made using Silverlight 2. In this part I will cover how the data is retrieved.
First off, the Xbox Friends Watch series of experiments would not be possible without the existence of the Xbox Gamertag Data Service. The service provides both SOAP and REST based access and I'll being showing you how the REST-based service was used within the application.
Get the data
When the application loads it looks within the InitParams parameters for a gamertag Key. The value is then passed to a RequestGamerXML function that creates a WebClient instance and queues and asynchronous request to the Gamertag Data service.
public void RequestGamerXml(string gamerTag)
{
string xboxUrl = string.Format("http://duncanmackenzie.net/services/GetXboxInfo.aspx?GamerTag={0}", gamerTag);
WebClient xboxService = new WebClient();
xboxService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(xboxService_DownloadStringCompleted);
xboxService.DownloadStringAsync(new Uri(xboxUrl));
}
The completed event handler is then called once the request is complete, providing the opportunity to handle errors and pass the result string to a parsing function.
private void xboxService_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
loadGamer(e.Result);
}
else{...}
}
The WebClient class is perfect for simple requests like this, but for more advanced network requests check otu the HttpWebRequest class.
For more information on Networking check out Karen Corby's two networking part series (Part 1, Part 2) and Laurent Bugnion's Downloading Zipped files
From XML to objects
Now that the data has been returned from the REST service as string, the values need to be parsed for display. Luckily there just happens to be a new simple and fun way to do this using LINQ.
LINQ, new in Silverlight 2, is a huge topic in and of itself and there are many videos, screencasts and blog posts about it. In the context of the Gamercard application it is interesting because you can perform powerful language-integrated queries, sets and transforms. Specifically turning the string results into an XboxInfo class with all of its property values set and sub classes created and populated as well.
First take a look at the XML response: http://duncanmackenzie.net/services/GetXboxInfo.aspx?GamerTag=festive%20turkey
Looking at the XML you can get an idea of the backing classes needed to serialize and deserialize that data. The classes I've created have typed properties but otherwise very closely match to the XML result's schema.
The XML string is used to create a new XDocument instance which can then be queried against to return an XboxInfo instance:
XDocument xDoc = XDocument.Parse(xmlContent);
XboxInfo gamer = (from XboxInfo in xDoc.Descendants("XboxInfo")
select new XboxInfo
{
PresenceInfo = new PresenceInfo()
{
Info = (string)XboxInfo.Element("PresenceInfo").Element("Info"),
Info2 = (string)XboxInfo.Element("PresenceInfo").Element("Info2"),
Online = (string)XboxInfo.Element("PresenceInfo").Element("Online"),
StatusText = (string)XboxInfo.Element("PresenceInfo").Element("StatusText")
},
GamerTag = (string)XboxInfo.Element("Gamertag"),
ProfileUrl = (string)XboxInfo.Element("ProfileUrl"),
TileUrl = (string)XboxInfo.Element("TileUrl"),
GamerScore = (string)XboxInfo.Element("GamerScore"),
Zone = (string)XboxInfo.Element("Zone"),
RecentGames = (from XboxUserGameInfo in XboxInfo.Element("RecentGames").Descendants("XboxUserGameInfo")
select new XboxUserGameInfo
{
Game = new Game()
{
Name = (string)XboxUserGameInfo.Element("Game").Element("Name"),
Image32Url = (string)XboxUserGameInfo.Element("Game").Element("Image32Url"),
Image64Url = (string)XboxUserGameInfo.Element("Game").Element("Image64Url"),
TotalAchievements = (string)XboxUserGameInfo.Element("Game").Element("TotalAchievements"),
TotalGamerScore = (string)XboxUserGameInfo.Element("Game").Element("TotalGamerScore")
},
Achievements = (string)XboxUserGameInfo.Element("Achievements"),
GamerScore = (string)XboxUserGameInfo.Element("GamerScore"),
DetailsURL = (string)XboxUserGameInfo.Element("DetailsURL"),
LastPlayed = (DateTime)XboxUserGameInfo.Element("LastPlayed")
}).Take(5).ToList()
}).First();
That may look like a mouthful but if you compare the XML results and the query you can see the relationship between the two. The end result a fully populated XboxInfo object that can be used to update the interface.
For more information on LINQ read the overview on MSDN and Scott Guthrie's tutorial Using LINQ with ASP.NET
Other parts in this series are available:
Building the Gamercard Part 1, Composing the UI Building the Gamercard Part 3, Updating the UI
silverlight+networking, silverlight