C#将XML响应映射到未知类

时间:2015-07-14 17:52:23

标签: c# xml generics reflection xml-serialization

我试图通过任何方式(IP,串行文本文件等)实现发送和接收XML的通用解决方案

所有似乎都能正常工作,直到我得到响应字符串。

我需要做的是将此响应强制转换为正确的类类型(LoginResponse,LogoffResponse,CardPaymentResponse) 等。

我无法以一种通用的方式将这个XMl以有效的方式重新投射到对象中。

到目前为止我得到了什么:

示例响应字符串:

LoginResponse的XML:

<?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"/>

LogoffResponse的XML:

<?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"/>

CardPaymentResponse的XML:

<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>

包含公共字段的基类代码

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类型,此处没有其他字段

public class ServiceResponse : IFSFResponseBase
{

}

CardServiceResponse类型,这里的公共字段

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
{

}

具体的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("CardServiceResponse")]
public class CardPaymentResponse : CardServiceResponse
{

}

具体的CardPaymentRefundResponse类,需要一些额外的数据

[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)。

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;
}

对于Logoff Response类型,这是好的,但如果它是LoginResponse类型则​​不行。

所以我可以使用LoginResponse,但如果响应是CardServiceResponse,这将失败并出现异常 因为Root元素不是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;
    }

先谢谢

0 个答案:

没有答案