C# Mapping XML Response into Unknown Class -
i'm trying achieve generic solution sending , receiving xml via means(ip, serial textfiles, etc)
all appears work fine until response string.
what need cast response sting correct class type (loginresponse, logoffresponse, cardpaymentresponse) etc.
i cant generic way cast xml object in efficient manner.
heres have got far:
sample response strings:
xml 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 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 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 base class 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 { { return this.valuefield; } set { this.valuefield = value; } } }
concrete logoffresponse class, no additional fields
[xmlroot("serviceresponse")] public class logoffresponse : serviceresponse { }
concrete loginresponse class, 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, data needed
[xmlroot("cardserviceresponse")] public class cardpaymentrefundresponse : cardserviceresponse { [xmlattribute()] public string extravalue { get; set; } }
helper class remove name space response
public class namespaceignorantxmltextreader : xmltextreader { public namespaceignorantxmltextreader(system.io.textreader reader) : base(reader) { } public override string namespaceuri { { return ""; } } }
with code below, don't know actual response receive until parsed, don't know can use in place of concrete class (in 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 debugging atm, removed throw; }
that fine logoff response type, not if loginresponse type.
so use loginresponse if response cardserviceresponse fail exception since root element not serviceresponse 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 debugging atm, removed throw; }
i tried following hack , work i'm wondering if there better way 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 requesttype name + response appended on, class //probably not exist. lets create 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
Comments
Post a Comment