Generating XML from multiple classes? - c#

i have another question on getting my XML serialization neat, which i can't seem to get right. my config file is as follows:
namespace SMCProcessMonitor
{
[Serializable()]
[XmlRoot("Email-Settings")]
public class Config
{
[XmlElement("Recipient")]
public string recipient;
[XmlElement("Server-port")]
public int serverport;
[XmlElement("Username")]
public string username;
[XmlElement("Password")]
public string password;
[XmlElement("Program")]
public List<Programs> mPrograms = new List<Programs>();
public string serialId;
}
public class Email
{
public string Recipient
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.recipient;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.recipient = value;
}
}
public int ServerPort
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.serverport;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.serverport = value;
}
}
public string Username
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.username;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.username = value;
}
}
public string Password { get; set; }
}
[Serializable()]
public class Programs
{
[XmlElement("Filename")] public string mFileName { get; set; }
[XmlElement("Filepath")]public string mFilePath { get; set; }
}
public class Database
{
public string mSerial { get; set; }
}
}
Ideally what i want to do is have each of these three classes (email settings, database and programs) have their own tags, like so
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<email-settings>
<Recipient>sadh</Recipient>
<Server-port>23</Server-port>
<Username>lkms</Username>
<Password>kmkdvm</Password>
</email-settings>
<Program>
<Filename>MerlinAlarm.exe</Filename>
<Filepath>D:\Merlin\Initsys\Merlin\Bin\MerlinAlarm.exe</Filepath>
</Program>
<database-settings>
<serialId>1</serialId>
</database-settings>
</Config>
But instead i get something that resembles this:
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Recipient>blah</Recipient>
<Server-port>1111</Server-port>
<Username>blah</Username>
<Password>blah</Password>
<Program>
<Filename>chrome.exe</Filename>
<Filepath>
C:\Users\Shane\AppData\Local\Google\Chrome\Application\chrome.exe
</Filepath>
</Program>
<serialId>1234</serialId>
</Config>
Sorry to be such a bother, but this is doing my nut in now and im sure there's some fundamental logic i'm missing here..can anyone give me some pointers as to how to get this XML in the format i specified above?
Thanks in advance, Shane.
Edit: My serialization class.
namespace SMCProcessMonitor
{
public class ShanesXMLserializer
{
private string mFileAndPath;
public Config mConfigurations = null;
public Config mConfigurationsProgram = null;
public ShanesXMLserializer(string inFileAndPath)
{
mFileAndPath = inFileAndPath;
mConfigurations = new Config();
}
public bool Write()
{
try
{
XmlSerializer x = new XmlSerializer(mConfigurations.GetType());
StreamWriter writer = new StreamWriter(mFileAndPath);
x.Serialize(writer, mConfigurations);
writer.Close();
return true;
}
catch (Exception ex)
{
MessageBox.Show("Exception found while writing: " + ex.Message);
};
return false;
}
public bool Read()
{
try
{
XmlSerializer x = new XmlSerializer(typeof(Config));
StreamReader reader = new StreamReader(mFileAndPath);
mConfigurations = (Config)x.Deserialize(reader);
reader.Close();
return true;
}
catch (Exception ex)
{
MessageBox.Show("Exception found while reading: " + ex.Message);
};
return false;
}
public Config GetConfigEmail
{
get
{
return mConfigurations;
}
}
}
}
Edit 2:
My new config file:
#Craig - I'm using this config file, which is like you said but im still not getting the desired XML, shown after my config class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.Text;
namespace SMCProcessMonitor
{
[Serializable()]
public class Config
{
public string recipient;
public int serverport;
public string username;
public string password;
public List<Programs> mPrograms = new List<Programs>();
public string serialId;
[XmlElement("email-settings")]
public Email Email { get; set; }
public Programs Programs { get; set; }
[XmlElement("database-settings")]
public Database Database { get; set; }
}
public class Email
{
[XmlElement("Recipient")]
public string Recipient { get; set; }
[XmlElement("Server-port")]
public int ServerPort { get; set; }
[XmlElement("Username")]
public string Username { get; set; }
[XmlElement("Password")]
public string Password { get; set; }
}
[Serializable()]
public class Programs
{
[XmlElement("Filename")] public string mFileName { get; set; }
[XmlElement("Filepath")]public string mFilePath { get; set; }
}
public class Database
{
[XmlElement("SerialID")]
public string mSerial { get; set; }
}
}
But i am still getting:
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<recipient>shane</recipient>
<serverport>23</serverport>
<username>oid</username>
<password>jidj</password>
<mPrograms/>
</Config>

This will give you the desired output:
public class Config
{
[XmlElement("email-settings")]
public Email Email { get; set; }
public Program Program { get; set; }
[XmlElement("database-settings")]
public Database Database { get; set; }
}
public class Email
{
public string Recipient { get; set; }
[XmlElement("Server-port")]
public int ServerPort { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public class Program
{
public string Filename { get; set; }
public string Filepath { get; set; }
}
public class Database
{
public string serialId { get; set; }
}
Here's a console application which will serialize an object to a file and produce the exact XML you are looking for. Just copy and paste it into a console application and take it from there.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var config = new Config
{
Email = new Email
{
Recipient = "sadh",
ServerPort = 23,
Username = "lkms",
Password = "kmkdvm"
},
Program = new Programs
{
Filename = "MerlinAlarm.exe",
Filepath = #"D:\Merlin\Initsys\Merlin\Bin\MerlinAlarm.exe"
},
Database = new Database
{
serialId = "1"
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Config));
var textWriter = new StreamWriter(#"C:\config.xml");
serializer.Serialize(textWriter, config);
textWriter.Close();
Console.Read();
}
}
#region [Classes]
public class Config
{
[XmlElement("email-settings")]
public Email Email { get; set; }
public Programs Program { get; set; }
[XmlElement("database-settings")]
public Database Database { get; set; }
}
public class Email
{
public string Recipient { get; set; }
[XmlElement("Server-port")]
public int ServerPort { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public class Programs
{
public string Filename { get; set; }
public string Filepath { get; set; }
}
public class Database
{
public string serialId { get; set; }
}
#endregion
}

I'm going to suggest a totally sideways approach here, just for simplicity's and maintenance's sake.
What if you took the source XML file and generated an XSD schema?
For instance:
xsd.exe MyXMLFile1.xml
This will generate an XML schema file (MyXMLFile1.xsd). Take the schema and generate classes (again using xsd.exe):
xsd.exe /c MyXMLFile1.xsd
This will generate a guaranteed serializable POCO that you can use going forward. The class names and properties may not match what you have in your current POCO but it will generate the expected XML, as well as deserialize from the XML.
The added benefit is that going forward, you will only have to modify the source XML file, then run these 2 commands to maintain the POCO.
Hope that helps...

Related

Not sure how to access nested XML in C#

I'm attempting to deserialize an XML file into corresponding C# objects. I've read through the other answers and I'm at a loss as to what I'm doing wrong.
Here's my XML file
<?xml version="1.0" encoding="utf-8"?>
<DialogueObjectCollection>
<DialogueObjects>
<DialogueObject id="0001">
<name>CHARACTER</name>
<dialogue>
<text tag="1">Hi, this is a message.</text>
<text tag="2">Yup.</text>
<text tag="3">What do you want to do?
<options>
<option action= "1">Go back.</option>
<option action="4">Tell me something new.</option>
</options>
</text>
<text tag= "4">This is the end.</text>
</dialogue>
</DialogueObject>
<DialogueObject id="0002">
<name>CHARACTER2</name>
<dialogue>
<text tag="1">Hi.</text>
</dialogue>
</DialogueObject>
</DialogueObjects>
</DialogueObjectCollection>
Here are my classes:
{
[Serializable(), XmlRoot("DialogueObject")]
public class DialogueObject
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlElement("name")]
public string name { get; set; }
[XmlAttribute("tag")]
public int tag { get; set; }
public OptionHolder option;
public DialogueHolder dialogueHolder { get; set; }
[XmlAttribute("action")]
public string action { get; set; }
}
[Serializable(), XmlRoot("dialogue")]
public class DialogueHolder
{
[XmlArray("dialogue")]
[XmlArrayItem("text", IsNullable = false)]
public TextItem[] dialogue { get; set; }
}
[Serializable(),XmlRoot("text")]
public class TextItem
{
[XmlAttribute]
public string tag { get; set; }
public string text { get; set; }
}
[Serializable(),XmlRoot("option")]
public class OptionHolder
{
[XmlAttribute]
public string action;
[XmlElement("option")]
public string option;
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("DialogueObjectCollection")]
public class DialogueObjectCollection
{
[XmlArray("DialogueObjects")]
[XmlArrayItem("DialogueObject", typeof(DialogueObject))]
public DialogueObject[] dialogueObject { get; set; }
}
And my method:
public static void LoadDialogue()
{
DialogueObjectCollection dialogueCollection = null;
string path = "Content/NPCdata.xml";
XmlSerializer serializer = new XmlSerializer(typeof(DialogueObjectCollection));
Console.WriteLine("LOADDINGGGG");
StreamReader reader = new StreamReader(path);
dialogueCollection = (DialogueObjectCollection)serializer.Deserialize(reader);
//test print Console.WriteLine(dialogueCollection.dialogueObject.First().dialogueHolder.dialogue.First().text);
}
So, it's telling me that dialogueHolder is returning null. I can get the dialogueObject.First().name and id to print. I can't figure out why the dialogue text isn't loading into it. (My attempts at fixing it included adding the XmlRootNode attributes and adding more classes-- I'm new to XML serialization in C#)
Thanks for any help!
try code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication3
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
LoadDialogue(FILENAME);
}
public static void LoadDialogue(string path)
{
XmlReader reader = XmlReader.Create(path);
XmlSerializer serializer = new XmlSerializer(typeof(DialogueObjectCollection));
DialogueObjectCollection dialogueObjectCollection = (DialogueObjectCollection)serializer.Deserialize(reader);
}
}
[Serializable(), XmlRoot("DialogueObject")]
public class DialogueObject
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlElement("name")]
public string name { get; set; }
[XmlAttribute("tag")]
public int tag { get; set; }
public OptionHolder option;
[XmlElement("dialogue")]
public DialogueHolder dialogueHolder { get; set; }
[XmlAttribute("action")]
public string action { get; set; }
}
[Serializable(), XmlRoot("dialogue")]
public class DialogueHolder
{
[XmlElement("text")]
public TextItem[] texItem { get; set; }
}
[Serializable(), XmlRoot("text")]
public class TextItem
{
[XmlAttribute]
public string tag { get; set; }
[XmlText()]
public string text { get; set; }
[XmlArray("options")]
[XmlArrayItem("option")]
public OptionHolder[] options { get; set; }
}
[Serializable(), XmlRoot("option")]
public class OptionHolder
{
[XmlAttribute]
public string action;
[XmlElement("option")]
public string option;
}
[XmlRoot("DialogueObjectCollection")]
public class DialogueObjectCollection
{
[XmlArray("DialogueObjects")]
[XmlArrayItem ("DialogueObject")]
public DialogueObject[] dialogueObject { get; set; }
}
}

Issues Deserializing Xml in C#

I'm following the tutorial given here for deserializing an embedded xml document.
My Xml doc:
<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfAgency xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbAgencyDefinition>
<Name>RTD</Name>
<Country>USA</Country>
<City>Denver</City>
<State>CO</State>
<GtfsZipUrlDirectory>http://www.address.com/etc/</GtfsZipUrlDirectory>
<GtfsZipUrlFileName>file_name.zip</GtfsZipUrlFileName>
</DbAgencyDefinition>
</ArrayOfAgency>
My class I'm deserializing to:
public class DbAgencyDefinition
{
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string GtfsZipUrlDirectory { get; set; }
public string GtfsZipUrlFileName { get; set; }
public string State { get; set; }
}
The code that's trying to deserialize the XML to a list of DbAgencyDefinition:
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(DbAgencyDefinition)).Assembly;
Stream stream = assembly.GetManifestResourceStream("MyNamespace.Resources.xml.AgencyDefinitions.xml");
var agencies = new List<DbAgencyDefinition>();
using (var reader = new StreamReader(stream))
{
var serializer = new XmlSerializer(typeof(List<DbAgencyDefinition>));
agencies = (List<DbAgencyDefinition>)serializer.Deserialize(reader);
}
The error I'm getting is:
System.Exception: There is an error in XML document. <ArrayOfAgency xmlns=''> was not expected
I've tried a million things with the XML, marking the class as Serializable, and it always returns this error. I looked at the code samples that the tutorial gives and I can't figure out why I'm getting this error.
VS for Windows, and maybe on Mac as well, has a special tool that will convert copied Xml into autogenerated classes. Now, it's not perfect but if you take your Xml file it generates a couple of classes similar to this:
public class ArrayOfAgency
{
public ArrayOfAgencyDbAgencyDefinition DbAgencyDefinition { get; set; }
}
public class ArrayOfAgencyDbAgencyDefinition
{
public string Name { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string State { get; set; }
public string GtfsZipUrlDirectory { get; set; }
public string GtfsZipUrlFileName { get; set; }
}
As you might notice ArrayOfAgency is determined as a class holding a DbAgencyDefinition, which is why it's throwing an error while trying to deserialize it directly into a List<DbAgencyDefinition>. The type and what the serializer is expecting are not quite the same.
var serializer = new XmlSerializer(typeof(ArrayOfAgency));
var agencies = ((ArrayOfAgency)serializer.Deserialize(reader)).DbAgencyDefinition;
Also, as I mentioned the auto-generation may not be perfect because ArrayOfAgency may need to hold an array instead of a direct class if there can be more than one DbAgencyDefinition possible in Xml.
public class ArrayOfAgency
{
public ArrayOfAgencyDbAgencyDefinition[] DbAgencyDefinition { get; set; }
}
If you need more help or info on Xml Serialization check out the docs.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication120
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
using (var reader = new StreamReader(FILENAME, Encoding.UTF8))
{
var serializer = new XmlSerializer(typeof(ArrayOfAgency));
ArrayOfAgency agencies = (ArrayOfAgency)serializer.Deserialize(reader);
}
}
}
public class ArrayOfAgency
{
public DbAgencyDefinition DbAgencyDefinition { get; set; }
}
public class DbAgencyDefinition
{
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string GtfsZipUrlDirectory { get; set; }
public string GtfsZipUrlFileName { get; set; }
public string State { get; set; }
}
}

Write List<object> to XML file with elements and attribute

I have the following class:
[XmlType("supervisor")]
public class Supervisor
{
[XmlAttribute("id")]
public string Id { set; get; }
[XmlElement("Name")]
public string Name { set; get; }
[XmlElement("Contract")]
public int Contracts { set; get; }
[XmlElement("Volume")]
public long Volume { set; get; }
[XmlElement("Average")]
public int Average { set; get; }
}
which reads from XML file:
<digital-sales xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<supervisor id="1236674">
<Name>Hiroki</Name>
<Contract>11</Contract>
<Volume>1036253</Volume>
<Average>94205</Average>
</supervisor>
<supervisor id="123459">
<Name>Ayumi</Name>
<Contract>5</Contract>
<Volume>626038</Volume>
<Average>125208</Average>
</supervisor> ...
</digital-sales>
in the code I create List and process it.
now I want to write the List to XML file while maintaining the
same XML structure. How do I do that?
How to use xml id to fill class object?
Here is the code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication98
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(DigitalSales));
DigitalSales digitalSales = (DigitalSales)serializer.Deserialize(reader);
reader.Close();
XmlWriter writer = XmlWriter.Create(FILENAME);
serializer.Serialize(writer, digitalSales);
}
}
[XmlRoot("digital-sales")]
public class DigitalSales
{
[XmlElement("supervisor")]
public List<Supervisor> supervisor { get; set; }
}
[XmlRoot("supervisor")]
public class Supervisor
{
[XmlAttribute("id")]
public string Id { set; get; }
[XmlElement("Name")]
public string Name { set; get; }
[XmlElement("Contract")]
public int Contracts { set; get; }
[XmlElement("Volume")]
public long Volume { set; get; }
[XmlElement("Average")]
public int Average { set; get; }
}
}

Deserialize multiple XML tags to single C# object

I have class structure as follows
public class Common
{
public int price { get; set; }
public string color { get; set; }
}
public class SampleProduct:Common
{
public string sample1 { get; set; }
public string sample2 { get; set; }
public string sample3 { get; set; }
}
I have XML file as follows
<ConfigData>
<Common>
<price>1234</price>
<color>pink</color>
</Common>
<SampleProduct>
<sample1>new</sample1>
<sample2>new</sample2>
<sample3>new123</sample3>
</SampleProduct>
</ConfigData>
Now I wanted to deserialize full XML data to SampleProduct object (single object).I can deserialize XML data to different object but not in a single object. Please help.
If you create the XML yourself Just do it like this:
<ConfigData>
<SampleProduct>
<price>1234</price>
<color>pink</color>
<sample1>new</sample1>
<sample2>new</sample2>
<sample3>new123</sample3>
</SampleProduct>
</ConfigData>
Otherwise, if you get the XML from other sources, do what Kayani suggested in his comment:
public class ConfigData
{
public Common { get; set; }
public SampleProduct { get; set; }
}
But don't forget that the SampleProduct created in this manner don't have "price" and "color" properties and these should be set using created Common instance
Here is the complete solution using the provided XML from you.
public static void Main(string[] args)
{
DeserializeXml(#"C:\sample.xml");
}
public static void DeserializeXml(string xmlPath)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(ConfigData));
using (var xmlFile = new FileStream(xmlPath, FileMode.Open))
{
var configDataOSinglebject = (ConfigData)xmlSerializer.Deserialize(xmlFile);
xmlFile.Close();
}
}
catch (Exception e)
{
throw new ArgumentException("Something went wrong while interpreting the xml file: " + e.Message);
}
}
[XmlRoot("ConfigData")]
public class ConfigData
{
[XmlElement("Common")]
public Common Common { get; set; }
[XmlElement("SampleProduct")]
public SampleProduct XSampleProduct { get; set; }
}
public class Common
{
[XmlElement("price")]
public string Price { get; set; }
[XmlElement("color")]
public string Color { get; set; }
}
public class SampleProduct
{
[XmlElement("sample1")]
public string Sample1 { get; set; }
[XmlElement("sample2")]
public string Sample2 { get; set; }
[XmlElement("sample3")]
public string Sample3 { get; set; }
}
This will give you a single Object with all the elements you need.

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

Categories

Resources