[Update: This question is different from the suggested duplicate because this one is about deserialization of XML and the explanation of the problem and solution on this one is clearer as I've included the full source code.]
I'm trying to read and subsequently manipulate a response from a Web API. Its response looks like this:
<MYAPI xsi:noNamespaceSchemaLocation="MYAPI.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MySite Resource="some resource name">
<Name>some name</Name>
<URL>some url</URL>
<SecondName>Describes something</SecondName>
</MySite>
... A lot of these <MySite>...</MySite> are there
<SomeOtherSite Resource="some resource name">
<Name>some name</Name>
<URL>some url</URL>
</SomeOtherSite>
</MYAPI>
SomeOtherSite
is not repeating and only one of it appears at the end of the response. But the MySite
is the one that is repeating.
I've modeled the class for this XML response as:
public class MYAPI
{
public List<MySite> MySite { get; set; }
public SomeOtherSite SomeOtherSite { get; set; }
}
public class MySite
{
public string Name { get; set; }
public string URL { get; set; }
public string SecondName { get; set; }
}
public class SomeOtherSite
{
public string Name { get; set; }
public string URL { get; set; }
}
And this is my code:
static void Main()
{
var handler = new HttpClientHandler();
handler.Credentials = new NetworkCredential("MyUsername", "MyPassword");
var client = new HttpClient(handler);
client.BaseAddress = new Uri("https://sitename.com:PortNumber/");
var formatters = new List<MediaTypeFormatter>()
{
new XmlMediaTypeFormatter(){ UseXmlSerializer = true }
};
var myApi = new MYAPI();
HttpResponseMessage response = client.GetAsync("/api/mysites").Result;
if (response.IsSuccessStatusCode)
{
myApi = response.Content.ReadAsAsync<MYAPI>(formatters).Result;
}
}
Now the myApi
only has object for SomeOtherSite
but the list for the MySite
is empty.
Would someone please tell me how I should deserialize this response correctly?
Should I be creating custom media formatter? I have no idea of it by the way.
Also would you please tell me how to model that Resource
attribute coming in the response?
And I can't change anything in the WebAPI server. I just need to consume the data from it and use it elsewhere.
Thank You so much!
I solved this after some really good direction from: https://stackoverflow.com/users/1124565/amura-cxg Much Thanks!
The solution was to annotate all the properties with XMLAttributes. And it correctly deserialized the response. And as for the Resource
attribute, all I needed was [XmlAttribute(AttributeName="Resource")]
The rest of the source code works as is.
[XmlRoot(ElementName="MYAPI")]
public class MYAPI
{
[XmlElement(ElementName="MySite")]
public List<MySite> MySite { get; set; }
[XmlElement(ElementName="SomeOtherSite")]
public SomeOtherSite SomeOtherSite { get; set; }
}
public class MySite
{
[XmlElement(ElementName="Name")]
public string Name { get; set; }
[XmlElement(ElementName="URL")]
public string URL { get; set; }
[XmlElement(ElementName="SecondName")]
public string SecondName { get; set; }
[XmlAttribute(AttributeName="Resource")]
public string Resource { get; set; }
}
Plus, I didn't need any custom media formatter. And from one of the posts by https://stackoverflow.com/users/1855967/elisabeth , I learned that we should not touch the generated file from xsd.exe tool. So I explicitly set to use the XmlSerializer
instead of the DataContractSerializer
used by default:
var formatters = new List<MediaTypeFormatter>()
{
new XmlMediaTypeFormatter(){ UseXmlSerializer = true }
};