简体   繁体   English

DataContract 序列化程序不反序列化为没有容器元素的重复 XML 元素的列表

[英]DataContract serializer not deserializing into a list repeating XML elements without container element

We are facing a situation where the DataContract serializer (a WCF service) is not deserializing repeating XML elements without container element into a list;我们面临的情况是DataContract序列化程序(WCF 服务)没有将没有容器元素的重复 XML 元素反序列化到列表中; the list property ends up with zero elements. list 属性以零元素结束。

The datacontracts we have:我们拥有的数据合约:

[DataContract]
public class Requestor
{
    [DataMember(IsRequired = true, Order = 0)]
    public string RequestorRole;

    [DataMember(IsRequired = true, Order = 1)]
    public string RequestorGivenName;

    [DataMember(IsRequired = true, Order = 2)]
    public string RequestorSurName;

    [DataMember(IsRequired = false, Order = 3)] 
    public List<RequestorIdentification> RequestorIdentification { get; set; }
}

[DataContract]
public class RequestorIdentification
{
    [DataMember(IsRequired = true, Order = 0)]
    public string IdentificationID;

    [DataMember(IsRequired = true, Order = 1)]
    public string IdentificationCategoryCode;
}

The XML we want to deserialize:我们要反序列化的 XML:

 <Requestor xmlns="http://schemas.datacontract.org/2004/07/Serialization"> <RequestorRole>Physicians</RequestorRole> <RequestorGivenName>Rich</RequestorGivenName> <RequestorSurName>Smith</RequestorSurName> <RequestorIdentification> <IdentificationID>AB1234567</IdentificationID> <IdentificationCategoryCode>DEA</IdentificationCategoryCode> </RequestorIdentification> <RequestorIdentification> <IdentificationID>0123456789</IdentificationID> <IdentificationCategoryCode>NPI</IdentificationCategoryCode> </RequestorIdentification> </Requestor>

How can we resolve the issue using the DataContract serializer?我们如何使用DataContract序列化程序解决问题?

So far we have found no way to make it work, and this page https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/collection-types-in-data-contracts was not of much help.到目前为止,我们还没有找到让它工作的方法,而且这个页面https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/collection-types-in-data-contracts不是有很大帮助。

The same issue was resolved for the XmlSerializer in this question:此问题中的XmlSerializer解决了相同的问题:

Deserializing into a List without a container element in XML在 XML 中反序列化为没有容器元素的 List

To deserialize the XML shown in the OP, one can use XmlElement .要反序列化 OP 中显示的 XML,可以使用XmlElement However, this requires the use of XmlSerializer instead of DataContractSerializer for serialization and deserialization.但是,这需要使用XmlSerializer而不是DataContractSerializer进行序列化和反序列化。

According to this post根据这个帖子

The DataContractSerializer does not support the programming model used by the XmlSerializer and ASP.NET Web services. DataContractSerializer 不支持 XmlSerializer 和 ASP.NET Web 服务使用的编程模型。 In particular, it does not support attributes like XmlElementAttribute and XmlAttributeAttribute.特别是,它不支持 XmlElementAttribute 和 XmlAttributeAttribute 等属性。 To enable support for this programming model, WCF must be switched to use the XmlSerializer instead of the DataContractSerializer.若要启用对此编程模型的支持,必须将 WCF 切换为使用 XmlSerializer 而不是 DataContractSerializer。

The code below shows how one can deserialize the XML shown in the OP.下面的代码显示了如何反序列化 OP 中显示的 XML。

Create a Windows Forms App (.NET Framework)创建 Windows 窗体应用程序 (.NET Framework)

Add Reference (System.Runtime.Serialization)添加引用(System.Runtime.Serialization)

VS 2019 VS 2019

  • In VS menu, click Project在 VS 菜单中,单击项目
  • Select Add Reference...选择添加参考...
  • Click Assemblies单击程序集
  • Check System.Runtime.Serialization检查System.Runtime.Serialization
  • Click OK点击确定

The following using directives are used in the code below :以下代码中使用了以下 using 指令

  • using System;
  • using System.Collections.Generic;
  • using System.IO;
  • using System.Runtime.Serialization;
  • using System.Text;
  • using System.Xml;
  • using System.Xml.Serialization;

Create a class (name: RequestorRequestorIdentification.cs)创建一个类(名称:RequestorRequestorIdentification.cs)

[DataContract(Name = "RequestorIdentification")]
public class RequestorRequestorIdentification
{
    [DataMember]
    public string IdentificationID { get; set; }

    [DataMember]
    public string IdentificationCategoryCode { get; set; }
}

Create a class (name: Requestor.cs)创建一个类(名称:Requestor.cs)

[DataContract(Name ="Requestor")]
public class Requestor
{
    [DataMember]
    public string RequestorRole { get; set; }

    [DataMember]
    public string RequestorGivenName { get; set; }

    [DataMember]
    public string RequestorSurName { get; set; }

    [XmlElement]
    public List<RequestorRequestorIdentification> RequestorIdentification { get; set; } = new List<RequestorRequestorIdentification>();

}

Note : The use of XmlElement requires the use of XmlSerializer instead of DataContractSerializer for serialization and deserialization.注意:使用XmlElement需要使用XmlSerializer而不是DataContractSerializer进行序列化和反序列化。

Create a class (name: HelperXml.cs)创建一个类(名称:HelperXml.cs)

public class HelperXml
{
    public static T DeserializeXMLFileToObject<T>(string xmlFilename)
    {
        //usage: Requestor requestor = DeserializeXMLFileToObject<Requestor>(xmlFilename);

        if (String.IsNullOrEmpty(xmlFilename))
            throw new Exception("Error: xmlFilename is null or empty.");

        return DeserializeXMLToObject<T>(File.ReadAllBytes(xmlFilename));
    }

    public static T DeserializeXMLToObject<T>(string xmlText)
    {
        //usage: Requestor requestor = DeserializeXMLToObject<Requestor>(xmlText);

        //create new instance
        using (System.IO.StringReader reader = new System.IO.StringReader(xmlText))
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T), "http://schemas.datacontract.org/2004/07/Serialization");
            return (T)serializer.Deserialize(reader);
        }
    }

    public static T DeserializeXMLToObject<T>(byte[] xmlBytes)
    {
        //usage: Requestor requestor = DeserializeXMLToObject<Requestor>(File.ReadAllBytes(xmlFilename));

        //create new instance of MemoryStream
        using (MemoryStream ms = new MemoryStream(xmlBytes))
        {
            using (XmlTextReader reader = new XmlTextReader(ms))
            {
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T), "http://schemas.datacontract.org/2004/07/Serialization");
                return (T)serializer.Deserialize(reader);
            }
        }
    }
    public static void SerializeObjectToXMLFile(object obj, string xmlFilename)
    {
        //Usage: Class1 myClass1 = new Class1();
        //SerializeObjectToXMLFile(myClass1, xmlFilename);

        if (String.IsNullOrEmpty(xmlFilename))
            throw new Exception("Error: xmlFilename is null or empty.");

        //Xml writer settings
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.Encoding = Encoding.UTF8;
        settings.Indent = true;

        using (XmlWriter writer = XmlWriter.Create(xmlFilename, settings))
        {
            //specify namespaces
            System.Xml.Serialization.XmlSerializerNamespaces ns = new System.Xml.Serialization.XmlSerializerNamespaces();
            ns.Add(string.Empty, "http://schemas.datacontract.org/2004/07/Serialization");

            //create new instance
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType(), "http://schemas.datacontract.org/2004/07/Serialization");

            //write to XML file
            serializer.Serialize(writer, obj, ns);
        }
    }
}

Usage (deserialize):用法(反序列化):

private Requestor _requestor = null;
            ...

//deserialize
//_requestor = HelperXml.DeserializeXMLFileToObject<Requestor>(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Test.xml"));
//_requestor = HelperXml.DeserializeXMLToObject<Requestor>(System.Text.Encoding.UTF8.GetBytes(xmlText));
_requestor = HelperXml.DeserializeXMLToObject<Requestor>(xmlText);

Usage (serialize):用法(序列化):

private Requestor _requestor = null;
            ...

//create new instance
_requestor = new Requestor();

_requestor.RequestorRole = "Physicians";
_requestor.RequestorGivenName = "Rich";
-requestor.RequestorSurName = "Smith";

_requestor.RequestorIdentification.Add(new RequestorRequestorIdentification() { IdentificationID = "AB1234567", IdentificationCategoryCode = "DEA" });
_requestor.RequestorIdentification.Add(new RequestorRequestorIdentification() { IdentificationID = "0123456789", IdentificationCategoryCode = "NPI" });

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "XML File (*.xml)|*.xml";
    sfd.FileName = "Test.xml";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        HelperXml.SerializeObjectToXMLFile(_requestor, sfd.FileName);
        Debug.WriteLine($"Info: Saved to '{sfd.FileName}'");
    }
}

Additional Resources :其他资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM