0

We are facing a situation where the DataContract serializer (a WCF service) is not deserializing repeating XML elements without container element into a list; the list property ends up with zero elements.

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:

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

So far we have found no way to make it work, and this page https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/collection-types-in-data-contracts was not of much help.

The same issue was resolved for the XmlSerializer in this question:

Deserializing into a List without a container element in XML

Only You
  • 2,051
  • 1
  • 21
  • 34

1 Answers1

0

To deserialize the XML shown in the OP, one can use XmlElement. However, this requires the use of XmlSerializer instead of DataContractSerializer for serialization and deserialization.

According to this post

The DataContractSerializer does not support the programming model used by the XmlSerializer and ASP.NET Web services. In particular, it does not support attributes like XmlElementAttribute and XmlAttributeAttribute. To enable support for this programming model, WCF must be switched to use the XmlSerializer instead of the DataContractSerializer.

The code below shows how one can deserialize the XML shown in the OP.

Create a Windows Forms App (.NET Framework)

Add Reference (System.Runtime.Serialization)

VS 2019

  • In VS menu, click Project
  • Select Add Reference...
  • Click Assemblies
  • Check System.Runtime.Serialization
  • Click OK

The following using directives are used in the code below:

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

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

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

Create a class (name: 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.

Create a class (name: 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:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24