The online racing simulator
JSON .NET Deserializer issues...
Has anyone had any luck using the .NET DataContractJsonSerializer class to deserialize the LFSWorld pubstat data? I was thinking it would be cool if it worked, but nothing is happening and I'm not getting any error messages. This is the code I'm using, trying to get the PST stats.

[DataContract]
public class PlayerStats
{
[DataMember(Name = "distance")]
public string Distance { get; set; }

[DataMember(Name = "fuel")]
public string Fuel { get; set; }

[DataMember(Name = "laps")]
public string Laps { get; set; }

[DataMember(Name = "joined")]
public string Joined { get; set; }

[DataMember(Name = "win")]
public string Win { get; set; }

[DataMember(Name = "second")]
public string Second { get; set; }

[DataMember(Name = "third")]
public string Third { get; set; }

[DataMember(Name = "races_finished")]
public string RacesFinished { get; set; }

[DataMember(Name = "qual")]
public string Qual { get; set; }

[DataMember(Name = "pole")]
public string Pole { get; set; }

[DataMember(Name = "drags")]
public string Drags { get; set; }

[DataMember(Name = "dragwins")]
public string DragWins { get; set; }

[DataMember(Name = "country")]
public string Country { get; set; }

[DataMember(Name = "ostatus")]
public string OStatus { get; set; }

[DataMember(Name = "hostname")]
public string HostName { get; set; }

[DataMember(Name = "last_time")]
public string LastTime { get; set; }

[DataMember(Name = "track")]
public string Track { get; set; }

[DataMember(Name = "car")]
public string Car { get; set; }
}

That is my data contact, now here is the serialization code.

public PlayerStats GetPlayerStats(string identKey, string racer)
{
var uri = new Uri(string.Format(@"http://www.lfsworld.net/pubstat/get_stat2.php?version=1.4&idk={0}&action=pst&racer={1}&s=1", identKey, racer));
var request = WebRequest.Create(uri);
var response = request.GetResponse();
using (var stream = response.GetResponseStream())
{
var json = new DataContractJsonSerializer(typeof(PlayerStats));
return json.ReadObject(stream) as PlayerStats;
}
}

But as I say I'm getting nothing, no errors or anything, just lots of nulls.
OK - I've figured this out. All the JSON stuff from LFSWorld is returned as a list, even if there is only a single entry, so instead of deserializing a type of PlayerStats, you need to deserialize a type of List<PlayerStats>. So basically the code above gets changed to this:

public PlayerStats GetPlayerStats(string identKey, string racer)
{
var uri = new Uri(string.Format(@"http://www.lfsworld.net/pubstat/get_stat2.php?version=1.4&idk={0}&action=pst&racer={1}&s=1", identKey, racer));
var request = WebRequest.Create(uri);
var response = request.GetResponse();

using (var stream = response.GetResponseStream())
{
var json = new DataContractJsonSerializer(typeof(List<PlayerStats>));

var stats = (List<PlayerStats>)json.ReadObject(stream);

return stats.Single();
}
}

The code converts a pubstat response to a .NET object perfectly.
The JSON deserializer works really well actually. I've written a little LFSWorld object that can handle doing the queries for you and returns a decoded JSON object.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;

namespace LfsWorldExample
{
public class LfsWorld
{
private string _identKey;

public LfsWorld(string identKey)
{
_identKey = identKey;
}

public Uri CreatePubStatUrl(object args)
{
var url = new StringBuilder();
url.AppendFormat(
"http://www.lfsworld.net/pubstat/get_stat2.php?version=1.4&idk={0}&s=1",
_identKey);

foreach (var property in args.GetType().GetProperties())
{
url.AppendFormat(
"&{0}={1}",
property.Name,
property.GetValue(args, null));
}

return new Uri(url.ToString());
}

public Stream GetResponse(Uri url)
{
var request = WebRequest.Create(url);
var response = request.GetResponse();
return response.GetResponseStream();
}

public T GetJsonResponse<T>(Uri url)
{
using (var stream = GetResponse(url))
{
var json = new DataContractJsonSerializer(typeof(T));
return (T)json.ReadObject(stream);
}
}

public IQueryable<T> Query<T>(object args)
{
var url = CreatePubStatUrl(args);

return GetJsonResponse<List<T>>(url).AsQueryable();
}
}
}

To use it you first of all need to create a data-contract for the JSON results you want to deserialize, which at its simplest is basically just an object with each property named after the corresponding JSON field in the pubstat response.

Here is a very simple data-contract for the host list.

[DataContract]
public class Host
{
[DataMember]
public string hostname;
[DataMember]
public string tmlt;
[DataMember]
public string tcrm;
[DataMember]
public int cars;
[DataMember]
public int rules;
[DataMember]
public int laps;
[DataMember]
public int qualmins;
[DataMember]
public string country;
[DataMember]
public int nrracers;
[DataMember]
public List<string> racers; // It supports lists
}

Then you can create simple queries to request the list of hosts like this.

var lfs = new LfsWorld("<your ident key>");

var hosts = lfs.Query<Host>(new
{
action = "hosts",
});

The query is returned as a type of IQueryable, so you can perform LINQ operations on it. For instance if you wanted to get a list of only the populated hosts (hosts with one or more drivers) you could do a simple query like this.

var lfs = new LfsWorld("<your ident key>");

var hosts = lfs.Query<Host>(new
{
action = "hosts",
});

var populatedHosts = from h in hosts
where h.nrracers > 0
orderby h.nrracers descending
select h;

foreach (var host in populatedHosts)
{
Console.WriteLine(host.hostname);
}

You can pass multiple arguments into the query method, so to request a list of a players personal bests you could do this:

var lfs = new LfsWorld("<your ident key">);

var pbs = lfs.Query<PersonalBest>(new
{
action = "pb",
racer = "DarkTimes",
});

foreach (var pb in pbs)
{
// etc..
}

Or to request the hotlaps for a specific car and track.

var lfs = new LfsWorld("<your ident key>");

var hotlaps = lfs.Query<HotLap>(new
{
action = "ch",
track = "BL1",
car = "FBM",
});

My name is Dygear, and I approve this API!

Nice work mate .
This is really nice i was looking into it but could not find a solution thanks DarkTimes

FGED GREDG RDFGDR GSFDG