I must deserialize some xml to object class which I generate from xsd files using xsd.exe. Everything is okey but one part in my object is always null and I don't know why because in xml it have data.
It's the xml file:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<jdf:root xmlns:jdf="http://www.tmp.com/jdf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<jdf:header>
<jdf:trace-id>string</jdf:trace-id>
<jdf:timestamp>string</jdf:timestamp>
<jdf:command>string</jdf:command>
<jdf:version>string</jdf:version>
</jdf:header>
<even:data xmlns:even="http://tmp.com/zzz/pivot/event">
<even:event xmlns:com="http://tmp.com/zzz/utils/components">
<even:eventId>3</even:eventId>
<even:distributorId>string</even:distributorId>
<even:distributionNetworkId>string</even:distributionNetworkId>
<even:typology>string</even:typology>
</even:event>
</even:data>
</jdf:root>
And this is my class from xsd files:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.tmp.com/jdf")]
[System.Xml.Serialization.XmlRootAttribute("root", Namespace = "http://www.tmp.com/jdf", IsNullable = false)]
public partial class JdfRoot
{
private JdfHeader headerField;
private object dataField;
/// <uwagi/>
public JdfHeader header
{
get
{
return this.headerField;
}
set
{
this.headerField = value;
}
}
/// <uwagi/>
public object data
{
get
{
return this.dataField;
}
set
{
this.dataField = value;
}
}
}
/// <uwagi/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://mib.bnpp.com/cle/pivot/event")]
[System.Xml.Serialization.XmlRootAttribute("data", Namespace = "http://tmp.com/cle/pivot/event", IsNullable = false)]
public partial class T_data
{
private EventOut eventField;
/// <uwagi/>
public EventOut #event
{
get
{
return this.eventField;
}
set
{
this.eventField = value;
}
}
}
I left only the most necessary part because full version i very long.
You need to set the XML namespace for the data property correctly by applying XmlElementAttribute:
private T_data dataField;
[XmlElement("data", Namespace = "http://tmp.com/zzz/pivot/event")]
public T_data data
{
get
{
return this.dataField;
}
set
{
this.dataField = value;
}
}
Also, as Richard Schneider wrote, change the type of data to be T_data. If you leave it as an object property your even:data element tree will be deserialized as an XmlNode [] array which is probably not what you want.
(The easiest way to find and fix "XML property deserialized as null" bugs is to create an example of the class in memory, serialize to XML, and compare the output with your input XML. Usually you'll spot the difference; often it's an incorrect namespace.)
In JdfRoot, change public object data to public T_data data.
Related
I generated classes using xsd.exe and I got over 40 classes:
Link : https://www.pastiebin.com/5cc3253981ff6
And now I want to only deserialize adres
That's my deserializer:
XmlSerializer serializer = new XmlSerializer(typeof(Adres));
using (StringReader reader = new StringReader(xmlDocumentText))
{
Adres info = (Adres)(serializer.Deserialize(reader));
}
But I got error There is an error in XML document (1, 40)
Below is only part of XML(the whole takes 15MB):
https://www.pastiebin.com/5cc325c457a55
Your code should look like this
XmlSerializer serializer = new XmlSerializer(typeof(DomainClass.wpisyWpis));
using (StringReader reader = new StringReader(xmlDocumentText))
{
DomainClass.wpisyWpis info = (DomainClass.wpisyWpis)(serializer.Deserialize(reader));
}
You also need to add XmlRoot above this class :
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[XmlRoot("wpis")]
public partial class wpisyWpis
{
private Dokument dokumentField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Namespace = "http://asseco.pl/xml/rpm/ksiegaPraktyka/2011/04/08/")]
public Dokument Dokument
{
get
{
return this.dokumentField;
}
set
{
this.dokumentField = value;
}
}
}
I am generating .cs files from .xsd files using xsd.exe. But when I am adding the files to windows 10 universal blank app, I was getting error as "missing an assembly reference" for System.SerializableAttribute() and System.ComponentModel.DesignerCategoryAttribute("code"). I fixed this by #t.ouvre's trick. Then there were no errors in any of the particular line of the code but when i am building the code i am getting an error saying that " Cannot find type System.ComponentModel.MarshalByValueComponent in module System.dll" and it doesn't specify exactly where the error is. How can I use the file generated by xsd.exe in windows 10 universal app? What are all the things that I need to do with the file to use it for serialization and deserialization (using DataContractSerializer in UWP)
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class request
{
private usertype userField;
private string versionField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public usertype user
{
get
{
return this.userField;
}
set
{
this.userField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string version
{
get
{
return this.versionField;
}
set
{
this.versionField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class usertype
{
private string emailField;
private string passwordField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string email
{
get
{
return this.emailField;
}
set
{
this.emailField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string password
{
get
{
return this.passwordField;
}
set
{
this.passwordField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class NewDataSet
{
private request[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("request")]
public request[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
}
You can fake missing classes (System.SerializableAttribute(),System.ComponentModel.DesignerCategoryAttribute), just add new files with theses classes definitions :
namespace System
{
internal class SerializableAttribute : Attribute
{
}
}
namespace System.ComponentModel
{
internal class DesignerCategoryAttribute : Attribute
{
public DesignerCategoryAttribute(string _) { }
}
}
for serialization and deserialization, you have to use System.Runtime.Serialization.DataContractSerializer. For example :
DataContractSerializer serializer = new DataContractSerializer(typeof(request));
var r = new request { version = "test" };
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, r);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms))
{
string xmlContent = sr.ReadToEnd();
Debug.WriteLine(xmlContent);
ms.Seek(0, SeekOrigin.Begin);
using (XmlReader reader = XmlReader.Create(sr))
{
var deserialized = serializer.ReadObject(reader) as request;
if (deserialized != null && deserialized.version == r.version)
{
Debug.WriteLine("ok");
}
}
}
}
SerializableAttribute()
and DesignerCategoryAttribute
aren't supported in the uwp apps.
To produce a successful class that can be copied directly into the UWP ap , use the following tip :
This is done in a UWP app so u can just go ahead and do this.
Well the XML serialization does have some limitations that is you must have a default constructor without any parameters.
if you are planing to serialize a class that doesn't have a constructor microsoft encourages to use DataContractSerializer for such use cases.
Now the code is quite simple
First instantiate the obj to serialize.
Make a new XmlSerializer object.
Then the XmlWriter obj , since it takes in many different writer classes and u Need to instantiate one i've chosen string builder for demo purposes.
Then just simply call serialize on the serializer obj passing in your obj and the xmlwriter and the xml writer produces the op in the string builder obj.
Then i just turn it into a string.. from here u can do anything with the xml .. save it or play with it ..
the last toUpper method was just added bcoz i needed a line for debug point .. it's not necessary at all ...
private void Button_Click( object sender , RoutedEventArgs e )
{
Animal a = new Animal("Sheep" , 4);
XmlSerializer m = new XmlSerializer(typeof(Animal));
StringBuilder op = new StringBuilder();
var x = XmlWriter.Create(op);
m.Serialize(x , a);
string s = op.ToString();
var p = s.ToUpper();
}
public class Animal
{
public Animal( string name , int legcount )
{
this.name = name;
this.legcount = legcount;
}
public Animal()
{
this.name = "default";
this.legcount = 10000000;
}
public string name { get; set; }
public int legcount { get; set; }
}
The reult of the Serialized class
<?xml version="1.0" encoding="utf-16"?>
<Animal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<name>Sheep</name>
<legcount>4</legcount>
</Animal>
UPDATE: By this method you can first copy all of your serialized classes into the app and deserialize them when necessary inside the app.
Now all you need to do is copy your xml into ur new app and implement deserilization using the same techniques i've shown above.
This is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE paymentService PUBLIC "-//WorldPay//DTD WorldPay PaymentService v1//EN"
"http://dtd.worldpay.com/paymentService_v1.dtd">
<paymentService version="1.4" merchantCode="ABC">
<reply>
<error code="4">
<![CDATA[Security violation]]>
</error>
</reply>
</paymentService>
I'm deserializing it into classes created using the XSD they provided:
var responseStreamReader = new StreamReader(response.GetResponseStream());
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "paymentService";
XmlSerializer mySerializer = new XmlSerializer(typeof(paymentService), xRoot);
var someResponse = (paymentService) mySerializer.Deserialize(responseStreamReader);
It deserializes the paymentService, version, merchantCode, but the Item property is null.
This is part of the schema:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/worldpa
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/worldpay", IsNullable = false
public partial class paymentService
{
private object itemField;
private paymentServiceVersion versionField;
private string merchantCodeField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("inquiry", typeof (inquiry))]
[System.Xml.Serialization.XmlElementAttribute("modify", typeof (modify))]
[System.Xml.Serialization.XmlElementAttribute("notify", typeof (notify))]
[System.Xml.Serialization.XmlElementAttribute("reply", typeof (reply))]
[System.Xml.Serialization.XmlElementAttribute("submit", typeof (submit))]
[System.Xml.Serialization.XmlElementAttribute("verify", typeof (verify))]
public object Item
{
get { return this.itemField; }
set { this.itemField = value; }
}
/// <remarks/>
[System.Xml.Serialization.XmlAttribute]
public paymentServiceVersion version
{
get { return this.versionField; }
set { this.versionField = value; }
}
/// <remarks/>
[System.Xml.Serialization.XmlAttribute(DataType = "NMTOKEN")]
public string merchantCode
{
get { return this.merchantCodeField; }
set { this.merchantCodeField = value; }
}
}
I would expect the Item to be a reply object.
What could I be doing wrong?
I've fixed this, possibly not in the best way, but for the benefit of others..
I just removed the namespaces from everything.
My schema was generated with XSD.exe and I removed all references to Namespace = "http://tempuri.org/worldpay", and this fixed it. It also meant I didn't have to mess around with the XmlRootAttribute.
UPDATE 1
The problem is not multiple namespace.
I dont know why, but if create the object from generated class, assigned Signature field manually and serialize the object, the namespace of Signature node node is :
<Signature xmlns="http://www.abrasf.org.br/nfse.xsd">
instead
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
If i assign the xml usign certificate, the namespace of Signature is
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
With the first namespace, i can deseralizate without problem, but i need to sign.
Generated Class from wsdl using wsdl.exe
WSDL
EnviarLoteRpsEnvio of nfse.xsd
EnviarLoteRpsEnvio class:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.abrasf.org.br/nfse.xsd")]
public partial class EnviarLoteRpsEnvio
{
private tcLoteRps loteRpsField;
private SignatureType signatureField;
/// <remarks/>
public tcLoteRps LoteRps
{
get { return this.loteRpsField; }
set { this.loteRpsField = value; }
}
/// <remarks/>
public SignatureType Signature
{
get { return this.signatureField; }
set { this.signatureField = value; }
}
}
SignatureTypeClass:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2000/09/xmldsig#")]
public partial class SignatureType {
private SignedInfoType signedInfoField;
private SignatureValueType signatureValueField;
private KeyInfoType keyInfoField;
private ObjectType[] objectField;
private string idField;
/// <remarks/>
public SignedInfoType SignedInfo {
get {
return this.signedInfoField;
}
set {
this.signedInfoField = value;
}
}
/// <remarks/>
public SignatureValueType SignatureValue {
get {
return this.signatureValueField;
}
set {
this.signatureValueField = value;
}
}
From the generated classes, was generated the follow xml :
But when i try to deserealize this xml, using the function:
public static object DeserializarParaObjeto(string xmlStr, Type tipo)
{
TextReader tx = new StringReader(xmlStr);
XmlSerializer deSerializer = new XmlSerializer(tipo);
deSerializer.UnknownAttribute += deSerializer_UnknownAttribute;
deSerializer.UnknownElement += deSerializer_UnknownElement;
deSerializer.UnknownNode += deSerializer_UnknownNode;
deSerializer.UnreferencedObject += deSerializer_UnreferencedObject;
return deSerializer.Deserialize(tx);
}
The event deSerializer_UnknownNode is invoked ( node unknow, Signature ).
The object is generated, but the node signature is not assigned.
This happens because the xml contains multiple namespaces?
What i need to do in this case ?
Ps: I don't post all xml and schemas because is too large.
I solve my problem, in fact the problem was not my.
I needed to edit manually the class generated by wsdl.exe and add XmlRootAttribute on :
partial class EnviarLoteRpsEnvio:
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.abrasf.org.br/nfse.xsd", IsNullable = false)]
Partial class Signature:
[System.Xml.Serialization.XmlRootAttribute("Signature", Namespace = "http://www.w3.org/2000/09/xmldsig#", IsNullable = false)]
And on porperty
SignatureType Signature of partial class EnviarRpsEnvio:
[System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")]
I know that we must never alter the generated class, but i had no alternative in this case.
I'm generating >100 classes from a lot of XSD's to build our test harness application for internal testing. I'm using XSD.exe to generate these classes, as doing it by bring in too much risk and it would take way too long.
I'm having an issue that is causing me a bit of pain. I'm trying to get this enumeration (for now just this one, then I'll do the same technique on the remaining ones...)
What I would like is for this to generate something like this(where the receiver element has a typeCode attribute):
<receiver typeCode="RCV">
<device classCode="DEV" determinerCode="INSTANCE">
<id root="..." extension="..." />
<asAgent classCode="AGNT">
<representedOrganization classCode="ORG" determinerCode="INSTANCE">
<id root="..." extension="..." />
</representedOrganization>
</asAgent>
</device>
</receiver>
however, receiver never gets an attribute, even though I have explicetly set in the test harness startup object:
this.receiver = new MCCI_MT000100BCReceiver();
this.receiver.typeCode = CommunicationFunctionType.RSP;
this.receiver.device = new MCCI_MT000100BCDevice();
I have an enumeration (I've added the XMLEnums and the [Flags] attribute as XSD.exe didn't bother)
[Flags]
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "urn:hl7-org:v3")]
public enum CommunicationFunctionType
{
/// <remarks/>
[System.Xml.Serialization.XmlEnum("RCV")]
RCV = 1,
/// <remarks/>
[System.Xml.Serialization.XmlEnum("RSP")]
RSP = 2,
/// <remarks/>
[System.Xml.Serialization.XmlEnum("SND")]
SND = 3,
}
And this is one of the classes that use that enum:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(TypeName = "MCCI_MT000100BC.Receiver", Namespace = "urn:hl7-org:v3")]
public partial class MCCI_MT000100BCReceiver
{
private CS[] realmCodeField;
private II typeIdField;
private II[] templateIdField;
private MCCI_MT000100BCDevice deviceField;
private CommunicationFunctionType typeCodeField;
private bool typeCodeFieldSpecified;
public MCCI_MT000100BCReceiver()
{
this.typeCodeField = CommunicationFunctionType.RCV;
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("realmCode")]
public CS[] realmCode
{
get
{
return this.realmCodeField;
}
set
{
this.realmCodeField = value;
}
}
/// <remarks/>
public II typeId
{
get
{
return this.typeIdField;
}
set
{
this.typeIdField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("templateId")]
public II[] templateId
{
get
{
return this.templateIdField;
}
set
{
this.templateIdField = value;
}
}
/// <remarks/>
public MCCI_MT000100BCDevice device
{
get
{
return this.deviceField;
}
set
{
this.deviceField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public CommunicationFunctionType typeCode
{
get
{
return this.typeCodeField;
}
set
{
this.typeCodeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool typeCodeSpecified
{
get
{
return this.typeCodeFieldSpecified;
}
set
{
this.typeCodeFieldSpecified = value;
}
}
}
I understand that serializing enumerations isn't something .NET likes to do at times, but any help would be appreciated.
There is no problem with enums in .net/XML; the problem is simply that you (or xsd) have added a "typeCodeSpecified" member. This is a pattern that is used to conditionally include values - specifically, for a member called "Foo", the engine checks for either a "FooSpecified" property, or a "ShouldSerializeFoo()" method. Since you never set "typeCodeSpecified" to true, it will return false, and the member will be omitted during serialization.
If you didn't want that, remove this member.