I am working on a project where I communicate with an API service through both REST and Comet semantics.
XML
So, the problem at hand.
I receive this error when I try to deserialize the following XML.
Error at resolve type "xsi:SubscriptionEvent"
NetBike.Xml.TypeResolvers.XmlTypeResolveException
Note: I use NetBike, but the error exist in the default xml formatter too
<?xml version="1.0" encoding="UTF-8"?>
<xsi:Event
xsi1:type="xsi:SubscriptionEvent"
xmlns:xsi="http://schema.broadsoft.com/xsi"
xmlns:xsi1="http://www.w3.org/2001/XMLSchema-instance">
<xsi:eventID>0787e727-e73d-43e0-a7b1-e968ba72ea53</xsi:eventID>
<xsi:sequenceNumber>1</xsi:sequenceNumber>
<xsi:userId>11111111#voip.company.domain</xsi:userId>
<xsi:externalApplicationId>NewClient</xsi:externalApplicationId>
<xsi:subscriptionId>24def51b-21fb-4d60-a1ef-67477dcafcfb</xsi:subscriptionId>
<xsi:channelId>575cfe44-2cc7-4cf5-bc05-bcc462bcbb02</xsi:channelId>
<xsi:targetId>22222222#voip.company.domain</xsi:targetId>
<xsi:eventData xsi1:type="xsi:ACDSubscriptionEvent"/>
</xsi:Event>
I'm not a XML "Jedi knight", but I know the basics.
The errors tells me I have a problem with the type xsi1:type="xsi:SubscriptionEvent" this is the attribute on the root xml (Event) element, this is the three attributes in question.
xsi1:type="xsi:SubscriptionEvent"
xmlns:xsi="http://schema.broadsoft.com/xsi"
xmlns:xsi1="http://www.w3.org/2001/XMLSchema-instance"
C# Class
I am using C#, until now I have had no problems creating equivalent classes based on the XML returned to me upon development.
If I take out the "bad data" the exception is avoided.
Event Class (I'm using this in Web API V2 environment, so technically its a model)
[XmlRoot(ElementName = "Event", Namespace = "http://schema.broadsoft.com/xsi")]
public class Event
{
[XmlElement(ElementName = "eventID", Namespace = "http://schema.broadsoft.com/xsi")]
public string EventID { get; set; }
[XmlElement(ElementName = "sequenceNumber", Namespace = "http://schema.broadsoft.com/xsi")]
public string SequenceNumber { get; set; }
[XmlElement(ElementName = "userId", Namespace = "http://schema.broadsoft.com/xsi")]
public string UserId { get; set; }
[XmlElement(ElementName = "externalApplicationId", Namespace = "http://schema.broadsoft.com/xsi")]
public string ExternalApplicationId { get; set; }
[XmlElement(ElementName = "subscriptionId", Namespace = "http://schema.broadsoft.com/xsi")]
public string SubscriptionId { get; set; }
[XmlElement(ElementName = "channelId", Namespace = "http://schema.broadsoft.com/xsi")]
public string ChannelId { get; set; }
[XmlElement(ElementName = "targetId", Namespace = "http://schema.broadsoft.com/xsi")]
public string TargetId { get; set; }
[XmlElement(ElementName = "eventData", Namespace = "http://schema.broadsoft.com/xsi")]
public EventData eventData { get; set; }
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string xsi { get; set; }
[XmlAttribute(AttributeName = "xsi1", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi1 { get; set; }
[XmlRoot(ElementName = "eventData", Namespace = "http://schema.broadsoft.com/xsi")]
public class EventData
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
}
}
This class was mainly generated from http://xmltocsharp.azurewebsites.net/
(that greatly speeds up this otherwise dull task)
Valid XML?
When I run the XML through different XML validators, I get different responses, some validates the XML fine, and some don't.
http://www.xmlvalidation.com: Fail
http://www.validome.org/xml/validate: Fail
http://codebeautify.org/xmlvalidate: Ok
To me, I find it hard to comprehend how exactly the structure is supposed to work.
It seems like the type attribute should be built upon the xsi1 attribute, but everything I have tried have failed.
My last resort will be to read the response as a string, then strip off the annoying XML so that it can be deserialized properly.
Best regards.
A slightly frustrated developer in dire need of help.
I think the confusion has arisen because xsi:type is part of XML schema and defines the types of various elements. You're trying to treat it as a normal attribute, and the serialiser is trying to use it to determine what objects to map the data to. The objects it's looking for aren't defined in the model.
Essentially, you need to model your classes after the type hierarchy your XML implies. So you have a base Event class with a SubscriptionEvent sub-class, and you have a base EventData class with a ACDSubscriptionEvent sub-class.
Note that (at least for XmlSerializer), you can omit a lot of your namespaces as they're inherited from the parent. You probably know more about the hierarchy than I do, so some of the properties may be able to be moved into the base class etc. Ideally, you'd have the XML schema file (.xsd) and would be able to generate the classes using xsd.exe, but this will work for the given XML:
[XmlInclude(typeof(SubscriptionEvent))]
[XmlRoot(Namespace = "http://schema.broadsoft.com/xsi")]
public abstract class Event
{
}
[XmlType(Namespace = "http://schema.broadsoft.com/xsi")]
public class SubscriptionEvent : Event
{
[XmlElement(ElementName = "eventID")]
public string EventID { get; set; }
[XmlElement(ElementName = "sequenceNumber")]
public string SequenceNumber { get; set; }
[XmlElement(ElementName = "userId")]
public string UserId { get; set; }
[XmlElement(ElementName = "externalApplicationId")]
public string ExternalApplicationId { get; set; }
[XmlElement(ElementName = "subscriptionId")]
public string SubscriptionId { get; set; }
[XmlElement(ElementName = "channelId")]
public string ChannelId { get; set; }
[XmlElement(ElementName = "targetId")]
public string TargetId { get; set; }
[XmlElement(ElementName = "eventData")]
public EventData EventData { get; set; }
}
[XmlInclude(typeof(ACDSubscriptionEvent))]
public abstract class EventData
{
}
[XmlType(Namespace = "http://schema.broadsoft.com/xsi")]
public class ACDSubscriptionEvent : EventData
{
}
See this fiddle for a working demo (using XmlSerializer).
Related
Essentially I have a Root class to serialize/deserialize JSON data that looks like this:
public class Root
{
[JsonIgnore]
public string JoystickName { get; set; }
public Root(string joystickName)
{
JoystickName = joystickName;
}
[JsonProperty("g")]
public string G { get; set; }
[JsonProperty(PropertyName = JoystickName)] // This line produces error
public DxsJoyConfig Joystick { get; set; }
}
*EDIT:
How do I change the property name at runtime?
I'm also running into an object reference error required at the indicated line. How can I make an instance of JoystickName within the attribute?
XML to be deserialized:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<changes next="296">
<change>
<objectid>E702C43C-E04B-450B-BEBC-76646AB299C5</objectid>
<parentid>ED98C97F-A202-48ED-AEEA-34362508A30B</parentid>
<objecttype>file</objecttype>
<listentype>remove</listentype>
</change>
<change>
<objectid>3A242975-CEF0-432B-A997-B33D85C138C8</objectid>
<parentid>ED98C97F-A202-48ED-AEEA-34362508A30B</parentid>
<objecttype>file</objecttype>
<listentype>add</listentype>
</change>
</changes>
Data models used:
[XmlRoot("changes")]
public class ChangeListener
{
public List<Change> Changes { get; set; }
}
[XmlRoot("change")]
public class Change
{
[XmlElement("objectid")]
public Guid objectid { get; set; }
[XmlElement("parentid")]
public Guid parentid { get; set; }
[XmlElement("objecttype")]
public string objecttype { get; set; }
[XmlElement("listentype")]
public string listentype { get; set; }
}
Deserialization code, here result is above xml in string format:
(ChangeListener)new XmlSerializer(typeof(ChangeListener)).Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(result)))
But I am getting errors for this code; I also tried couple of things e.g. marked Changes property of ChangeListener class with [XmlElement("changes")] instead of marking class as xmlroot but it also did not worked.
Kindly suggest good approach for this issues.
The problem is that the Changes List in the ChangeListener is confusing the serializer because there's nothing called 'Changes' in the XML.
The only change we need to make is to annotate the declaration of Changes with [XmlElement("change")] as below:
[XmlRoot("changes")]
public class ChangeListener
{
[XmlElement("change")]
public List<Change> Changes { get; set; }
}
The XML shown then deserializes correctly.
The Class for mentioned XML should look like below.
[XmlRoot(ElementName="change")]
public class Change {
[XmlElement(ElementName="objectid")]
public string Objectid { get; set; }
[XmlElement(ElementName="parentid")]
public string Parentid { get; set; }
[XmlElement(ElementName="objecttype")]
public string Objecttype { get; set; }
[XmlElement(ElementName="listentype")]
public string Listentype { get; set; }
}
[XmlRoot(ElementName="changes")]
public class Changes {
[XmlElement(ElementName="change")]
public List<Change> Change { get; set; }
[XmlAttribute(AttributeName="next")]
public string Next { get; set; }
}
Try changing the type of objectid and parentid from Guid to string.
Share the error details if you still get errors.
I was searching for this issues but haven't found what I need. I need to use Entity Framework model in Web API for getting XML requests and responses.
I have two classes with a one-to-many relationship:
[Serializable]
[DataContract(Name = "shepherd")]
[KnownTypeAttribute(typeof(Sheep))]
public partial class Shepherd
{
public Shepherd()
{
this.Sheep = new HashSet<Sheep>();
}
[DataMember(Name = "shepherdId")]
//[XmlElement("shepherdId")]
public int Id { get; set; }
[DataMember(Name = "name")]
//[XmlElement("name")]
public string Name { get; set; }
[DataMember(Name = "isDeleted")]
//[XmlElement("IsDeleted")]
public Nullable<bool> IsDeleted { get; set; }
[DataMember(Name = "sheeps")]
//[XmlArray("sheeps"), XmlArrayItem("sheep")]
public virtual ICollection<Sheep> Sheep { get; set; }
}
and this is the second class:
[DataContract(Name = "sheep")]
[KnownType(typeof(Shepherd))]
public partial class Sheep
{
[DataMember(Name = "id")]
//[XmlElement("id")]
public int Id { get; set; }
[DataMember(Name = "colour")]
// [XmlElement("colour")]
public string Colour { get; set; }
[DataMember(Name = "createdon")]
//[XmlElement("CreatedOn")]
public Nullable<System.DateTime> CreatedOn { get; set; }
public int Shepherd { get; set; }
[IgnoreDataMember]
public virtual Shepherd Shepherd1 { get; set; }
}
and I always get this error:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
System.InvalidOperationException
Type 'System.Data.Entity.DynamicProxies.Shepherd_EF797FA5FAF7ACF0AF313B6DFF83AF6E5F2EE1AD57BC457F9C10E73BA5DEEFE6' with data contract name 'Shepherd_EF797FA5FAF7ACF0AF313B6DFF83AF6E5F2EE1AD57BC457F9C10E73BA5DEEFE6:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
I need to get only XML not Json
My class definition:
[Serializable]
public class MyClass
{
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int XXX_ID { get; set; }
[XmlElement(ElementName = "XXX")]
public string XXX_Value{ get; set; }
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int YYY_ID { get; set; }
[XmlElement(ElementName = "YYY")]
public string YYY_Value { get; set; }
}
My XML:
<MyClass>
<XXX ID="123">Some Values</XXX>
<YYY ID="567">Some Values</YYY>
</MyClass>
My Problem:
I want to de-serialize the above XML into an object.
During the runtime, an error has occurred, it is not allowed to have same attribute name in 2 different elements and under the same root.
How to solve this problem?
P/S: I cannot change the XML, I am not the owner of it.
Thanks in advance.
To do that you either need to do the (de)serialization manually, or you need to DTO to have roughly the same layout as the xml. For example:
public class Something { // need a name here to represent what this is!
[XmlAttribute] public int ID {get;set;}
[XmlText] public string Value {get;set;}
}
then
public class MyClass {
public Something XXX {get;set;}
public Something YYY {get;set;}
}
I am having a problem serializing via XML because 2 clases use a class (although different classes!) called Relationship. I have tried decorating 1 of the classes with another name using the XML attribute but it still gives me the following error:
{"Types 'SiteServer.Relationship' and 'LocalServer.Relationship' both use the XML type name, 'Relationship', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type."}
Here are my 2 classes, anyone know why ?? AM i using the wrong attribute? It seems to be ignoring it :-)
public class SiteServer
{
[XmlRoot("SiteServerRelationShip")]
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
public Relationship Relate = new Relationship();
}
public class LocalServer
{
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
public Relationship Relate = new Relationship();
}
Decorate your two classes by an XmlRoot like this :
[XmlRoot("SiteServer", Namespace="http://example.com/schemas/SiteServer")]
public class SiteServer
{
[XmlRoot("SiteServerRelationShip", Namespace="http://example.com/schemas/SiteServer")]
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
public Relationship Relate = new Relationship();
}
[XmlRoot("LocalServer", Namespace="http://example.com/schemas/LocalServer")]
public class LocalServer
{
[XmlRoot("LocalServerRelationship", Namespace="http://example.com/schemas/LocalServer")]
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
public Relationship Relate = new Relationship();
}
This will produce two different FQDN for the two RelationShip classes :
{http://example.com/schemas/LocalServer}LocalServerRelationShip
{http://example.com/schemas/SiteServer}SiteServerRelationShip
[XmlRoot] is only used for the root element of the document. You want to use [XmlType] on other types.
Also, you don't need [Serializable]. The XML Serializer ignores it.
You have to decorate the fields also, e.g.:
[XmlInclude(typeof(Relationship))]
public class SiteServer
{
[XmlRoot("SiteServerRelationship", Namespace = "http://example.com/schemas/SiteServerRelationship")]
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
[XmlElement("SiteServerRelationship", Namespace="http://example.com/schemas/SiteServerRelationship")]
public Relationship Relate = new Relationship();
}
[XmlInclude(typeof(Relationship))]
public class LocalServer
{
[XmlRoot("LocalServerRelationship", Namespace = "http://example.com/schemas/LocalServerRelationship")]
public class Relationship
{
public string type { get; set; }
}
public string Name { get; set; }
[XmlElement("LocalServerRelationship", Namespace="http://example.com/schemas/LocalServerRelationship")]
public Relationship Relate = new Relationship();
}
I had this problem with two 3rd party webservices I was consuming in one application. Strangely, the dynamic runtime generation was fine (although it took 2 minutes), but sgen.exe got upset.
The solution was to use svcutil.exe...
svcutil.exe /t:xmlSerializer targetAssemblyOrExecutable /out:targetAssemblyOrExecutable.XmlSerializers.dll.cs
Then use csc.exe to compile it.