XML deserialize derived class - c#

The problem is XmlType("Erand") name is same as my class Erand, if I changed the class name to like Eranda it worked, is there any other way to say .net what to do?
I have an class
public class Erand
{
public long ID { get; set; }
public string AsjaNumber { get; set; }
}
and
[XmlType("Erand")]
public class ErandTsiv : Erand
{
[XmlElement("ID_KIS")]
public long idKis { get; set; }
[XmlElement("ID_ET")]
public long idEt { get; set; }
}
I want to deserialize ErandTsiv
from xml like
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfErand xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Erand>
<ID>573838383</ID>
<ID_KIS>573838383</ID_KIS>
<ID_ET></ID_ET>
<AsjaNumber>2-08-88785</AsjaNumber>
</Erand>
</ArrayOfErand>
like
var stream = new StringReader(erandid);
var serializer = new XmlSerializer(new List<ErandTsiv>().GetType());
var erandTsivs = (IList<ErandTsiv>)serializer.Deserialize(stream);`
but get an error
{"There was an error reflecting type 'System.Collections.Generic.List`1[Aet.test.unit.application.utility.TsivTapsustaTest.ErandTsiv]'."}

To deserialize this exact XML you should rely on a custom List definition for your List<ErandTsiv>, leaving out the XmlType on ErandTsiv
Your class definitions would then be :
public class Erand
{
public long ID { get; set; }
public string AsjaNumber { get; set; }
}
public class ErandTsiv : Erand
{
[XmlElement("ID_KIS")]
public long idKis { get; set; }
[XmlElement("ID_ET")]
public long idEt { get; set; }
}
[XmlRoot("ArrayOfErand")]
public class ErandTsivList
{
public ErandTsivList()
{
Erands = new List<ErandTsiv>();
}
[XmlElement("Erand")]
public List<ErandTsiv> Erands { get; set; }
}
And the deserialization would be :
var stream = new StringReader(x);
var serializer = new XmlSerializer(typeof(ErandTsivList));
var erandTsivs = (ErandTsivList)serializer.Deserialize(stream);
// your List<ErandTsiv> would then be in erandTsivs.Erands

Related

Why an XML string cannot be deserialized due to prefixes in root elements?

I have the XML below:
<y:input xmlns:y='http://www.blahblah.com/engine/42'>
<y:datas>
<y:instance yclass='ReportPeriod' yid="report">
<language yid='en'/>
<threshold>0.6</threshold>
<typePeriod>predefinedPeriod</typePeriod>
<interval>month</interval>
<valuePeriod>April</valuePeriod>
<fund yclass="Fund">
<name>K</name>
<indexName>CAC40</indexName>
</fund>
</y:instance>
</y:datas>
</y:input>
That I am trying to deserialize to
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
public string Y { get; set; }
}
However, when deserializing the XML above:
public static class Program
{
public static void Main(params string[] args)
{
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StringReader(File.ReadAllText("file.xml")))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
var instance = (Input)serializer.Deserialize(stringReader);
}
}
}
}
I get an error due to the y prefix...
There is an error in XML document (1, 1). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
Reading some posts like that one: https://stackoverflow.com/a/36163079/4636721 it seems that there is maybe a bug with the XmlSerializer.
The cause of the exception is that you are passing stringReader rather than xmlReader to serializer.Deserialize(). You should be passing the XML reader instead:
Input instance = null;
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StreamReader("file.xml"))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
instance = (Input)serializer.Deserialize(xmlReader);
}
}
(Apparently XmlReader.Create(stringReader) advances the text reader a bit, so if you later attempt to read from the stringReader directly, it has been moved past the root element.)
You also have some errors in your data model. It should look like:
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance")]
[XmlType(Namespace = "")] // Add this
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
//Remove This
//[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
//public string Y { get; set; }
}
// Add this
[XmlRoot(ElementName="language")]
public class Language
{
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
Notes:
xmlns:y='http://www.blahblah.com/engine/42' is an XML namespace declaration and thus should not be mapped to a member in the data model.
The child elements of <y:instance ...> are not in any namespace. Unless the namespace of the child elements is specified by attributes somehow, XmlSerializer will assume that they should be in the same namespace as the containing element, here http://www.blahblah.com/engine/42".
Thus it is necessary to add [XmlType(Namespace = "")] to Instance to indicate the correct namespace for all child elements created from Instance. (Another option would be to add [XmlElement(Form = XmlSchemaForm.Unqualified)] to each member, but I think it is easier to set a single attribute on the type.)
A definition for Language is not included in your question, so I included one.
It will be more efficient to deserialize directly from your file using a StreamReader than to read first into a string, then deserialize from the string using a StringReader.
Working sample fiddle here.

C# Mapping XML Response into Unknown Class

I'm trying to achieve a generic solution for sending and receiving XML via any means(IP, serial textfiles, etc)
All appears to work fine until i get the response String.
What i need to do is cast this response sting into the correct class type (LoginResponse, LogoffResponse, CardPaymentResponse)
etc.
I cant get a generic way to cast this XMl back into the object in an efficient manner.
Heres what i have got so far:
Sample Response Strings:
XML for LoginResponse:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ServiceResponse RequestType="Login" ApplicationSender="POSsel01" WorkstationID="1" RequestID="1254" ProtocolVersion="000000001234" DeviceType="113" SWChecksum="AC3F" CommunicationProtocol="000000000432" Model="011" ApplicatioSoftwareVersion="000000000100" Manufacturer_Id="023" OverallResult="Success" xmlns="http://www.nrf-arts.org/IXRetail/namespace" xmlns:IFSF="http://www.ifsf.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace C:\Schema\ServiceResponse.xsd"/>
XML for LogoffResponse:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ServiceResponse RequestType="Logoff" ApplicationSender="POSsel01" WorkstationID="1" RequestID="1254" OverallResult="Success"
xmlns="http://www.nrf-arts.org/IXRetail/namespace" xmlns:IFSF="http://www.ifsf.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace C:\Schema\ServiceResponse.xsd"/>
XML for CardPaymentResponse:
<CardServiceResponse
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
RequestType="CardPayment"
ApplicationSender="1"
WorkstationID="1"
RequestID="1254"
OverallResult="LoggedOut">
<Terminal
TerminalID="1234"
TerminalBatch="1"
STAN="55" />
<Tender>
<TotalAmount
Currency="EUR">0.00</TotalAmount>
</Tender>
</CardServiceResponse>
Code for Base class to contain common fields
public abstract class IFSFResponseBase
{
[XmlAttribute()]
public string RequestType { get; set; }
[XmlAttribute()]
public string ApplicationSender { get; set; }
[XmlAttribute()]
public string WorkstationID { get; set; }
[XmlAttribute()]
public string RequestID { get; set; }
[XmlAttribute()]
public string OverallResult { get; set; }
}
ServiceResponse Type, no additional fields here
public class ServiceResponse : IFSFResponseBase
{
}
CardServiceResponse Type, Common Fields here
public class CardServiceResponse : IFSFResponseBase
{
[XmlElement("Terminal")]
public CardServiceResponseTerminal Terminal
{ get; set; }
[XmlElement("Tender")]
public CardServiceResponseTender Tender
{
get; set;
}
}
CardServiceResponse Helper Classes
public class CardServiceResponseTerminal
{
[XmlAttribute()]
public string TerminalID { get; set; }
[XmlAttribute()]
public string TerminalBatchField { get; set; }
[XmlAttribute()]
public string STANField { get; set; }
}
public class CardServiceResponseTender
{
[XmlElement("TotalAmount")]
public CardServiceResponseTenderTotalAmount TotalAmount { get; set; }
}
public class CardServiceResponseTenderTotalAmount
{
private string valueField;
[XmlAttribute()]
public string CashBackAmount
{
get;
set;
}
[XmlAttribute()]
public string Currency
{
get;
set;
}
[XmlText()]
public string Value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
}
Concrete LogoffResponse Class, no additional fields
[XmlRoot("ServiceResponse")]
public class LogoffResponse : ServiceResponse
{
}
Concrete LoginResponse Class, extra fields handled
[XmlRoot("ServiceResponse")]
public class LoginResponse : ServiceResponse
{
[XmlAttribute()]
public string POPID { get; set; }
[XmlAttribute()]
public string ReferenceNumber { get; set; }
[XmlAttribute()]
public string ProtocolVersion { get; set; }
[XmlAttribute()]
public string DeviceType { get; set; }
[XmlAttribute()]
public string SWChecksum { get; set; }
[XmlAttribute()]
public string CommunicationProtocol { get; set; }
[XmlAttribute()]
public string Model { get; set; }
[XmlAttribute()]
public string ApplicatioSoftwareVersion { get; set; }
[XmlAttribute()]
public string Manufacturer_Id { get; set; }
}
Concrete CardPaymentResponse Class, no additional fields
[XmlRoot("CardServiceResponse")]
public class CardPaymentResponse : CardServiceResponse
{
}
Concrete CardPaymentRefundResponse Class, Some extra data needed
[XmlRoot("CardServiceResponse")]
public class CardPaymentRefundResponse : CardServiceResponse
{
[XmlAttribute()]
public string ExtraValue { get; set; }
}
Helper class to remove Name space from response
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
With the code below, I don't know the actual response I will receive until its parsed, so I don't
know what i can use in place of the concrete class (in this case ServiceResponse).
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ServiceResponse));
StringReader sr = new StringReader(XMLResponse);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (ServiceResponse)serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Breakpoint code here for debugging ATM, To BE REMOVED
throw;
}
That is fine for Logoff Response type, but not if it was a LoginResponse Type.
So I could Use LoginResponse but then if the response is a CardServiceResponse this will fail with an exception
since the Root element is not SERVICERESPONSE but CardServiceResponse
try
{
XmlSerializer serializer = new XmlSerializer(typeof(LoginResponse));
StringReader sr = new StringReader(XMLResponse);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (LoginResponse)serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Breakpoint code here for debugging ATM, To BE REMOVED
throw;
}
I tried the following hack and it will work but I'm wondering if there is a better way to achieve this
private object InternalParse(string sXML)
{
object oRetVal = null;
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(sXML);
XmlNode ReqType = xmlDoc.DocumentElement.Attributes.GetNamedItem("RequestType");
Assembly asm = Assembly.GetExecutingAssembly();
Type type = asm.GetType(asm.GetName().Name + "." + ReqType.Value + "Response");
object instance = null;
try
{
instance = (object)Activator.CreateInstance(type);
}
catch
{
//problem creating type from RequestType Name + Response appended on, the class
//probably does not exist. Lets create the parent class
type = asm.GetType(asm.GetName().Name + "." + xmlDoc.DocumentElement.Name);
instance = (object)Activator.CreateInstance(type);
}
XmlSerializer serializer = new XmlSerializer(instance.GetType());
StringReader sr = new StringReader(sXML);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
oRetVal = serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Log ex here
}
return oRetVal;
}
Thanks in Advance

How to Serialize Nested Classes and Collections into XML?

First, i tried on the internet different ways, but i didn't got what i want. i have viewmodel class with the following properties;
public class UserEntitySubmissionsReportViewModel
{
public UserEntitySubmissionsReportViewModel()
{
Submissions = new FinalUserEntitiesAssignmentViewModel();
}
public int Id { get; set; }
public int Status { get; set; }
public DateTime SubmissionDate { get; set; }
public int UserEntityAssignmentId { get; set; }
public FinalUserEntitiesAssignmentViewModel Submissions { get; set; }
}
and the nested class FinalUserEntitiesAssignmentViewModel whcih is;
[Serializable]
public class FinalUserEntitiesAssignmentViewModel
{
public FinalUserEntitiesAssignmentViewModel()
{
ProjectInformation = new ProjectInformationViewModel();
MilestoneInformation = new MilestoneInformationViewModel();
ActivityListInformation = new ActivityListInformationViewModel();
ActivityInformation = new ActivityInformationViewModel();
SubActivityInformation = new List<SubActivityInformationViewModel>();
}
[XmlElement(ElementName = "ProjectInformation")]
public ProjectInformationViewModel ProjectInformation { get; set; }
[XmlElement(ElementName = "MilestoneInformation")]
public MilestoneInformationViewModel MilestoneInformation { get; set; }
[XmlElement(ElementName = "ActivityListInformation")]
public ActivityListInformationViewModel ActivityListInformation { get; set; }
[XmlElement(ElementName = "ActivityInformation")]
public ActivityInformationViewModel ActivityInformation { get; set; }
[XmlElement(ElementName = "SubActivityInformation")]
public List<SubActivityInformationViewModel> SubActivityInformation { get; set; }
}
[Serializable]
public class ProjectInformationViewModel
{
[XmlElement(ElementName = "Id")]
public int Id { get; set; }
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
public string Description { get; set; }
}
When i serialize this, i only get the 1 property i.e Id for nested class.
var obj = new UserEntitySubmissionsReportViewModel();
var writer = new System.Xml.Serialization.XmlSerializer(typeof(UserEntitySubmissionsReportViewModel));
System.IO.StreamWriter file = new System.IO.StreamWriter(Server.MapPath("~/App_Data/UserEntitySubmissionsReportViewModel.xml"));
writer.Serialize(file, obj);
file.Close();
The result i get is;
<?xml version="1.0" encoding="utf-8"?>
<UserEntitySubmissionsReportViewModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>0</Id>
<Status>0</Status>
<SubmissionDate>0001-01-01T00:00:00</SubmissionDate>
<UserEntityAssignmentId>0</UserEntityAssignmentId>
<Submissions>
<ProjectInformation>
<Id>0</Id>
</ProjectInformation>
<MilestoneInformation>
<Id>0</Id>
</MilestoneInformation>
<ActivityListInformation>
<Id>0</Id>
</ActivityListInformation>
<ActivityInformation>
<Id>0</Id>
<Attributes />
<Tools />
</ActivityInformation>
</Submissions>
</UserEntitySubmissionsReportViewModel>
As you can see, i am not able to serialize other properties. Similarly i have nest collection too. How can i serialize nested properties using C# ?
I think that when serializing XML that you need to define a default constructor for your classes. Try adding a construction for your ProjectInformationViewModel class.
public class ProjectInformationViewModel
{
// Default Constructor
public ProjectInformationViewModel()
{
}
}

XML De-serialization giving null values

i am having an XML string like
<?xml version="1.0"?>
<FullServiceAddressCorrectionDelivery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AuthenticationInfo xmlns="http://www.usps.com/postalone/services/UserAuthenticationSchema">
<UserId xmlns="">FAPushService</UserId>
<UserPassword xmlns="">Password4Now</UserPassword>
</AuthenticationInfo>
</FullServiceAddressCorrectionDelivery>
In Order to map the nodes with Class, i am having the class structure like
[Serializable]
public class FullServiceAddressCorrectionDelivery
{
[XmlElement("AuthenticationInfo")]
public AuthenticationInfo AuthenticationInfo
{
get;
set;
}
}
[Serializable]
public class AuthenticationInfo
{
[XmlElement("UserId")]
public string UserId
{
get;
set;
}
[XmlElement("UserPassword")]
public string UserPassword
{
get;
set;
}
}
For De-serialization , i used xmlserializer to De-serialize the object
byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(xmlString);
MemoryStream stream = new MemoryStream(byteArray);
XmlSerializer xs = new XmlSerializer(typeof(FullServiceAddressCorrectionDelivery));
var result = (FullServiceAddressCorrectionDelivery)xs.Deserialize(stream);
but the value FullServiceAddressCorrectionDelivery object is always null..
please help me what i am doing wrong here....
Add namesapce on the XmlElement attribute as described here
[Serializable]
public class FullServiceAddressCorrectionDelivery
{
[XmlElement("AuthenticationInfo",
Namespace =
"http://www.usps.com/postalone/services/UserAuthenticationSchema")]
public AuthenticationInfo AuthenticationInfo
{
get;
set;
}
}
[Serializable]
public class AuthenticationInfo
{
[XmlElement("UserId", Namespace="")]
public string UserId
{
get;
set;
}
[XmlElement("UserPassword", Namespace = "")]
public string UserPassword
{
get;
set;
}
}

I need to know how to deserialize a specific XML into objects defined in a custom class in C#

Given the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<userAttributeList>
<attribute>
<userId>12345678</userId>
<attId>1234</attId>
<attName>Group</attName>
<attTypeId>8</attTypeId>
<attTypeName>User Group</attTypeName>
<attData>Member</attData>
</attribute>
<attribute>
<userId>12345678</userId>
<attId>1235</attId>
<attName>Contact Name</attName>
<attTypeId>16</attTypeId>
<attTypeName>Contact Center Greeting</attTypeName>
<attData>John Smith</attData>
</attribute>
...
</userAttributeList>
I want to deserialize it into the following classes:
[Serializable]
[XmlTypeAttribute(AnonymousType = true)]
public class UserAttributeList
{
[XmlArray(ElementName = "userAttributeList")]
[XmlArrayItem(ElementName = "attribute")]
public List<UserAttribute> attributes { get; set; }
public UserAttributeList()
{
attributes = new List<UserAttribute>();
}
}
[Serializable]
public class UserAttribute
{
public String userId { get; set; }
public String attId { get; set; }
public String attName { get; set; }
public String attTypeId { get; set; }
public String attTypeName { get; set; }
public String attData { get; set; }
}
Using the code below, where GetResponseStream() returns the XML object listed above:
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "userAttributeList";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(UserAttributeList), xRoot);
try
{
return (UserAttributeList)serializer.Deserialize(request.GetResponse().GetResponseStream());
}
catch (Exception exc)
{
return null;
}
My code compiles with no errors, but the UserAttributeList that is returned shows no child "attribute" items. No errors are thrown
I would sooner do something like:
public class userAttributeList
{
[XmlElement]
public List<UserAttribute> attribute { get; set; }
public UserAttributeList()
{
attribute = new List<UserAttribute>();
}
}
public class UserAttribute
{
public int userId { get; set; }
public int attId { get; set; }
public string attName { get; set; }
public int attTypeId { get; set; }
public string attTypeName { get; set; }
public string attData { get; set; }
}
Personally I'd use LinqToXsd. Take the existing xml, generate an xsd from it then use LinqToXsd to load that xml into a LinqToXsd object. Then you can do things like:
xml.company.com.reports.report.Load(xmlFileContents);
to build a POCO.

Categories

Resources