I’m on my first forray into ASP.NET Web API and I’ve got a problem which is causing me a great deal of frustration.
The RESTful service that I’m calling returns data such as:
<SearchResults xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Results>
<Result>
<Title>foo</Title>
</Result>
<Result>
<Title>bar</Title>
</Result>
</Results>
<NumberOfResults>2</NumberOfResults>
</SearchResults>
So I’ve created some entities to represent this data:
[Serializable, DataContract(Namespace = "")]
public class SearchResults
{
public List<Result> Results { get; set; }
public int NumberOfResults { get; set; }
}
[Serializable, DataContract(Namespace = "")]
public class Result
{
public string Title { get; set; }
}
And then I attempted to deserialize the data:
var client = new HttpClient();
client.BaseAddress = new Uri("some uri");
var response = client.GetAsync("/some/path/").Result;
response.EnsureSuccessStatusCode();
var result = response.Content.ReadAsAsync<SearchResults>().Result;
Which results in a SearchResults object with Results = null and NumberOfResults = 0 even though I know that there are results being returned, and if I check response.Content.ReadAsStringAsync(), the XML contains the results as expected.
I instead tried:
var serializer = new XmlSerializer(typeof(SearchResults));
var results = (SearchResults)serializer.Deserialize(response.Content.ReadAsStreamAsync().Result);
And that returned a fully populated SearchResults object.
Finally, I tried implementing a simple IFormatterLogger and passing that into ReadAsAsync, which got called if I tried to read the stream twice (as expected!), but doesn’t get called during a standard attempt at deserialization using ReadAsAsync.
I could just use an XmlSerializer and pass it the steam since that works, but that doesn’t seem as neat and tidy as using ReadAsAsync, plus I really want to know what I’m doing wrong 🙂
Updated 16:38BST 03/09/2012
Ok, I’m clearly missing something of vital importance when using Web API, but I still dont know what!
I’ve now tried consuming a service with a PUT verb, and whilst my entity serializes properly when I tested it using XmlSerializer the request was failing with an HTTP 500. I checked what was being sent with Fiddler and the XML generated by Web API looks nothing like that generated by XmlSerializer. For a start, everthing has names like “_x003C_Name_x003E_k__BackingField” rather than simply “Name”.
The weird “k__BackingField” names from my update have led me to the resolution, and as usual it was something very simple.
I’d forgotten to mark the properties in the entities with the DataMemberAttribute.
Marked them up and it all started working as I originally expected it to!
That was all it was!