C#将XML响应映射到未知类
我试图实现一个通用的解决方案,用于通过任何方式(IP、串行文本文件等)发送和接收XML 在我得到响应字符串之前,所有这些看起来都正常工作 我需要做的是将此响应类型转换为正确的类类型(LoginResponse、LogoffResponse、CardPaymentResponse) 等等 我无法找到一种通用的方法来以有效的方式将此XMl转换回对象 以下是我目前得到的信息: 响应字符串示例: 用于LoginResponse的XML:C#将XML响应映射到未知类,c#,xml,generics,reflection,xml-serialization,C#,Xml,Generics,Reflection,Xml Serialization,我试图实现一个通用的解决方案,用于通过任何方式(IP、串行文本文件等)发送和接收XML 在我得到响应字符串之前,所有这些看起来都正常工作 我需要做的是将此响应类型转换为正确的类类型(LoginResponse、LogoffResponse、CardPaymentResponse) 等等 我无法找到一种通用的方法来以有效的方式将此XMl转换回对象 以下是我目前得到的信息: 响应字符串示例: 用于LoginResponse的XML: <?xml version="1.0" encoding="
<?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"/>
ServiceResponse类型,此处没有其他字段
public class ServiceResponse : IFSFResponseBase
{
}
public class CardServiceResponse : IFSFResponseBase
{
[XmlElement("Terminal")]
public CardServiceResponseTerminal Terminal
{ get; set; }
[XmlElement("Tender")]
public CardServiceResponseTender Tender
{
get; set;
}
}
CardServiceResponse类型,此处为公共字段
public class ServiceResponse : IFSFResponseBase
{
}
public class CardServiceResponse : IFSFResponseBase
{
[XmlElement("Terminal")]
public CardServiceResponseTerminal Terminal
{ get; set; }
[XmlElement("Tender")]
public CardServiceResponseTender Tender
{
get; set;
}
}
CardServiceResponse帮助程序类
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;
}
}
}
具体LogoffResponse类,无其他字段
[XmlRoot("ServiceResponse")]
public class LogoffResponse : ServiceResponse
{
}
[XmlRoot("CardServiceResponse")]
public class CardPaymentResponse : CardServiceResponse
{
}
具体LoginResponse类,处理额外字段
[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; }
}
具体的CardPaymentResponse类,无其他字段
[XmlRoot("ServiceResponse")]
public class LogoffResponse : ServiceResponse
{
}
[XmlRoot("CardServiceResponse")]
public class CardPaymentResponse : CardServiceResponse
{
}
具体的CardPaymentReturnResponse类,需要一些额外的数据
[XmlRoot("CardServiceResponse")]
public class CardPaymentRefundResponse : CardServiceResponse
{
[XmlAttribute()]
public string ExtraValue { get; set; }
}
用于从响应中删除名称空间的帮助器类
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
对于下面的代码,在解析之前,我不知道将收到的实际响应,所以我不知道
知道我可以用什么来代替具体类(在本例中是ServiceResponse)
这对于注销响应类型来说很好,但如果它是LoginResponse类型就不行了
因此,我可以使用LoginResponse,但如果响应是CardServiceResponse,则会出现异常并失败
因为根元素不是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 for debugging ATM, To BE REMOVED
throw;
}
我尝试了下面的方法,它会起作用,但我想知道是否有更好的方法来实现这一点
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;
}
提前感谢找人阅读这么多代码很难。我听到了,但如果不至少显示这么多代码,就很难表达我想要的内容,我加载了更多的代码,我遗漏了这些代码只是为了表达问题的要点,基本上我检查XML字符串以确定要反序列化的类类型是否正确,反射是否过火了?更有效的方法??这看起来很合理,但是您可能会切换到更新的API。1) 使用
NamespaceIgnorantXmlTextReader将xml字符串加载到XDocument
;2) 从doc.Root.Name
确定对象类型;3) 按照此处的指定直接反序列化XDocument
: