Can't deserialize XML to object - c#

I'm having problems deserializing an XML response that I receive from a web service. The response looks like this:
<CreateSubscribersResultCollection xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CreatedSubscriberIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:long>206464306</a:long>
<a:long>306664316</a:long>
</CreatedSubscriberIds>
<FailedCreatedSubscribers xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
</CreateSubscribersResultCollection>
The code I use to deserialize the XML looks like this:
internal T GetQueuedResults<T>(string url)
{
WebRequest request = GetRequestObject(url, "GET");
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var responseStream = httpResponse.GetResponseStream())
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
var response = (T)xmlSerializer.Deserialize(responseStream);
return response;
}
}
When I deserialize (passing the type CreateSubscribersResultCollection) I get no errors at all, instead the CreatedSubscriberIds has the length of 0. I am pretty sure that the error lies in how I've designed the CreateSubscribersResultCollection class, but I can't figure out what the error might be. The class looks like this:
[DataContract]
public class CreateSubscribersResultCollection : RequestBase
{
[XmlArray("CreatedSubscriberIds")]
[XmlArrayItem(typeof(long))]
public List<long> CreatedSubscriberIds { get; set; }
[XmlElement("FailedCreatedSubscribers")]
public string FailedCreatedSubscribers { get; set; }
}
When I instantiate the class and serialize it, for debugging purposes, I get these results:
<CreateSubscribersResultCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CreatedSubscriberIds>
<long>206464306</long>
<long>306664316</long>
</CreatedSubscriberIds>
<FailedCreatedSubscribers />
</CreateSubscribersResultCollection>
I hope there's someone out there who knows what I'm doing wrong. I have been banging my head against this for too long now and Google has been no help to me.

Try specifying the namespace like that:
[DataContract]
public class CreateSubscribersResultCollection : RequestBase
{
[XmlArray("CreatedSubscriberIds")]
[XmlArrayItem(typeof(long), Namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public List<long> CreatedSubscriberIds { get; set; }
[XmlElement("FailedCreatedSubscribers")]
public string FailedCreatedSubscribers { get; set; }
}

Make sure you GetResponseStream() has a data in it. To test try saving this into a file instead of doing network connection. Save it to data file and deserialize. If it is being serialized, that is most of the battle. Deserializing shouldn't be problem if it was serialized properly.

Related

Error in xml document (1, 2) ... was not expected

I've tried several of the suggestions found on other SO answers for this same error but nothing has helped. Adding a namespace attr, using a blank namespace attr. Loading the string into an xmlDocument then rewriting it back to an xmlWriter. Using Serialazble instead of DataContract. Using xmlRoot attr with and without a namespace. Nothing works! Help.
I'm trying to instantiate a FillRequestExtended with the constructor that accepts an xml formatted string and always get the error Error in xml document (1, 2)
The Inner Exception reads: "http://schemas.datacontract.org/2004/07/WdRx.Exactus.Objects'> was not expected."
The class looks like so:
namespace WdRx.Exactus.Objects
{
[DataContract]
public class FillRequestExtended : IExtendedData
{
[DataMember]
[XmlElement]
public KeyValuePair<string, string>[] Properties { get; set; }
[DataMember]
[XmlElement]
public List<Payment> PaymentItems { get; set; }
public FillRequestExtended()
{
}
public FillRequestExtended(string xml)
{
FillRequestExtended extendedData;
XmlSerializer xs = new XmlSerializer(typeof(FillRequestExtended));
using (StringReader sr = new StringReader(xml))
{
XmlReader reader = XmlReader.Create(sr);
extendedData = (FillRequestExtended)xs.Deserialize(reader);
}
Properties = extendedData.Properties;
PaymentItems = new List<Payment>(extendedData.PaymentItems);
}
}
}
The string passed in is serialized elsewhere with no issue and looks like so:
<FillRequestExtended xmlns=\"http://schemas.datacontract.org/2004/07/WdRx.Exactus.Objects\"
xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">
<PaymentItems>
<Payment>
<Amount>-43.95</Amount>
<Summary>CCP PAYMENT - AUTH:014910</Summary>
</Payment>
<Payment>
<Amount>0.00</Amount>
<Summary>Type: VIS Account: ************5793 Expires: 05/16 Authorization: 014910</Summary>
</Payment>
</PaymentItems>
<Properties xmlns:a=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">
<a:KeyValuePairOfstringstring>
<a:key>RxDcDate</a:key>
<a:value>20150414</a:value>
</a:KeyValuePairOfstringstring>
<a:KeyValuePairOfstringstring>
<a:key>RefillStatus</a:key>
<a:value>PROFILED</a:value>
</a:KeyValuePairOfstringstring>
</Properties>
</FillRequestExtended>
There are at least two different XML deserializers. By decorating the class with [DataContract] you are forcing it to use the WCF serializer. In the deserialize code, you are using the normal XML object deserializer.

C# How to know which element is root object for deserialization?

I used json2csharp to get this:
http://pastebin.com/pbDYCrWk
From that, I wish to get the title that is held in the Oembed section.
I'm using this code:
string url = "http://www.reddit.com/r/all.json";
string jsonText = await DoStuff(url);
var json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonText);
var deserializeObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Page.Oembed>(json);
string test = deserializeObject.title;
And I assumed it would work, however on the line with the deserializeObject variable, I get an error saying it can't do it.
I tried using Page.RootObject however it doesn't work either, and I assumed it would since it seems to be the root.
What am I doing wrong and how can I solve it? Thanks.
If you used Json2CSharp then it is RootObject:
public class RootObject
{
public string kind { get; set; }
public Data data { get; set; }
}
Should be:
var deserializeObject = Newtonsoft.Json.JsonConvert.DeserializeObject<JuicyReddit.RootObject>(json);

RestSharp Deserialize returns empty properties but xml.deserialize test works

EDIT : the moment I asked the question I thougt of trying something..
I've set XmlNamespace property on the request and that did the trick..
request.XmlNamespace = "http://musicbrainz.org/ns/mmd-2.0#";
But I don't really understand as to why...
Next problem is getting RestSharp to recognize xml atributes as object properties
I've been going over this for the most of the weekend and I just don't get it to work.
I'm trying to write a wrapper round a RestFul webservice (MusicBrainz). I'm testing with a simple example : get details of one artist and put it in a custom Artist object.
When I do a Execute on the RestClient it ends ok but my object properties are null..
But when I test the deserialization with the XmlDeserializer the objectproperties are filled (But not for properties that correspond to an attribute, but I'll tackle that later)
What happens between deserialization of the response and putting the object in response.data ?
Quite possible it is a "newbie" error I'm making as this are my first steps with RestSharp..
Help would be much appreciated..
Returnded xml :
<metadata>
<artist type="Group" id="f1548c5b-329e-4036-921c-02213a04b525">
<name>Uriah Heep</name>
<sort-name>Uriah Heep</sort-name>
<country>GB</country>
<life-span>
<begin>1970</begin>
</life-span>
</artist>
</metadata>
My class :
public class Artist
{
public int Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string SortName { get; set; }
public string Country { get; set; }
}
In the following code output properties are filled
var output = xml.Deserialize<Artist>(response);
But the same response does not fill properties when calling
var response = client.Execute<T>(request);
Complete code (I've put the test code in the generic method for sake of simplicity) :
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient();
client.BaseUrl = BaseUrl;
client.Authenticator = null;
//does not fill properties
var response = client.Execute<T>(request);
if (response.ErrorException != null)
{
throw response.ErrorException;
}
var xml = new XmlDeserializer();
//fills properties
var output = xml.Deserialize<Artist>(response);
return response.Data;
}
This happens because Execute method, after receiving response, tries to negotiate it based on the request's RootElement and XmlNamespace properties and copies them to the XmlDeserializer.
Here's a code from RestClient:
handler.RootElement = request.RootElement;
handler.DateFormat = request.DateFormat;
handler.Namespace = request.XmlNamespace;
response.Data = handler.Deserialize<T>(raw);
If you pass a RestRequest with a mismatching XmlNamespace, RestSharp's XmlDeserializer (that uses XDocument behind the scenes) won't be able to map response XML to an object properties and you will get default/null values instead.
Now for default implementation (when you create XmlDeserializer manually), if you don't set a XmlNamespace, deserializer will do an auto-detection that basically ignores all namespaces in the response and maps all properties only by their names.
See source code from XmlDeserializer:
// autodetect xml namespace
if (!Namespace.HasValue())
{
RemoveNamespace(doc);
}
Taking all above into account, it's clear why it started working after you explicitly set XmlNamespace property to a matching namespace in your request object with this line:
request.XmlNamespace = "http://musicbrainz.org/ns/mmd-2.0#";
Execute method copied namespace into deserializer and it mapped XML to object appropriately.

Testing the Deserialization of RestSharp without proper REST-Api

EDIT: The solution to the question can be found in the first comment by John Sheehan!
i would like to use Restsharp as Rest-Client for my Project. Since the REST server is not running yet, I would like to test the client without the Server. My main focus is on the deserialization of the returning XML-Response. Is it possible to deserialize XML using RestSharp without a proper RestSharp.RestResponse?
I tried it like this:
public void testDeserialization()
{
XmlDeserializer d = new XmlDeserializer();
RestSharp.RestResponse response = new RestSharp.RestResponse();
string XML = #"<Response><Item1>Some text</Item1><Item2>Another text</Item2><Item3>Even more text</Item3></Response>";
response.Content = XML;
d.RootElement = "Response";
Response r = d.Deserialize<Response>(response);
}
public class Response
{
public string Item1 { get; set; }
public string Item2 { get; set; }
public string Item3 { get; set; }
}
The deserializations creates an Object of the Response-Class, where every field is null. Is there a way to test if (and how) any given xml would be deserialized by RestSharp?
Edit: For better readability - this is the XML i'm using:
<Response>
<Item1>Some text</Item1>
<Item2>Another text</Item2>
<Item3>Even more text</Item3>
</Response>
I hope I'm doing this right - but to make clear this question is solved, i'm copying the solutions (from the comments by John Sheehan):
You shouldn't have to specify RootElement. That's only for when the
root isn't at the top level. Try that and let me know if it works.
Here's how we test the deserializer for the project:
https://github.com/restsharp/RestSharp/blob/master/RestSharp.Tests/XmlDeserializerTests.cs
(EDIT: Updated link to correct file)

How to XmlDeserialize using RestSharp?

I'm having trouble deserializing the following XML w/ restsharp
<Xid>
<Id>118</Id>
<Active>true</Active>
<Xid>20</Xid>
<CreatedDate>2011-09-16T18:15:32</CreatedDate>
<CreatedUserId>1782</CreatedUserId>
<ModifiedDate>2011-09-16T18:15:32</ModifiedDate>
<ModifiedUserId>1782</ModifiedUserId>
<TableName>ProjectRate</TableName>
<ObjectId>644</ObjectId>
<SystemGuid>157f2e2d-5e8b-41c7-b932-09c1d75d0ccc</SystemGuid>
</Xid>
I can't use a class named 'Xid' with a member named 'Xid' as there is a conflict in C#. I have tried manually declaring the XmlRoot on the XidClass object, but it doesn't seem to be getting picked up by RestSharp's deserializer. Is there a way to do this with RestSharp, or am I going to need to write a custome deserializer for this particular chunk of xml?
You need to create the class by hand, befoe you can deserialize the XML:
public class Xid
{
public int Id { get; set; }
public bool Active { get; set; }
public int Xid { get; set; }
...
}
The you should be able to deserialize using something like:
Xid xid = xml.Deserialize<Xid>(response);
(Have a look here: Testing the Deserialization of RestSharp without proper REST-Api)

Categories

Resources