C # - Serializing Private Property as Attribute (Data Contract)

After learning I can't serialize private properties in class, I started using DataContract and DataMember annotations .

I have my own string property in my class that I would like to serialize as an attribute and not as an element.

[DataContract]
public class Channel
{
    private string m_Name = string.Empty;
    private DateTime? m_TxTime = null;

    [DataMember, XmlAttribute("name")]
    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            m_Name = value;
        }
    }

    public DateTime? TxTime
    {
        get
        {
            return m_TxTime;
        }
        set
        {
            m_TxTime = value;
        }
    }

    [DataMember, XmlAttribute("txTime")]
    private string txTimeForSerialization
    {
        get
        {
            if (TxTime.HasValue)
            {
                return TxTime.Value.ToString("o");
            }
            else
            {
                return null;
            }
        }
    }
}

      

Trying to use DataMember and XmlAttribute annotations together gave me this result:

<channel name="NAME">
   <TxTime>2017-03-26T13:15:56.8042989+03:00</TxTime>
</channel>

      

As a result, I want:

<channel name="NAME" txTime="2017-03-26T13:15:56.8042989+03:00" />

      

How do I serialize using XmlSerializer -

using (FileStream fs = new FileStream("channels.txt", FileMode.Create))
{
    XmlSerializer serializer = new XmlSerializer(typeof(Channel));
    serializer.Serialize(fs, objectName);
}

      

+3


source to share


2 answers


Create a "wrapper" for your class, which will be responsible for the correct deserialization format (some kind of facade template)

[DataContract]
public class ChannelData
{
    [DataMember, XmlAttribute("name")]
    public string Name { get; set; }

    [DataMember, XmlAttribute("txTime")]
    public string txTimeForSerialization { get; set; }
}

      

You can put the serialization instantiation logic in a class Channel

, then responsibility for the serialization logic will remain in the channel class - which preserve encapsulation.



public class Channel
{
    public string Name { get; set; }
    public DateTime? TxTime { get; set; }

    public Channel()
    {
        Name = string.Empty;
        TxtTime = null;
    }

    public ChannelData ToSerialization()
    {
        var data = new ChannelData();
        data.Name = Name;
        data.txTimeForSerialization = TxTime.HasValue ? TxTime.Value.ToString("o") : null;
    }
}

      

With a wrapper, you don't have to think about different "workarounds" for different formats, your "business-level" classes will remain "clear" and the wrappers will handle the formatting.

0


source


If you want to stick with your current class Channel

, you need to implement the interface IXmlSerializer

and its WriteXml method. This is the only way to serialize private properties through XmlSerializer

.

public class Channel : IXmlSerializable
{
    private string m_Name = string.Empty;
    private DateTime? m_TxTime = null;

    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            m_Name = value;
        }
    }

    public DateTime? TxTime
    {
        get
        {
            return m_TxTime;
        }
        set
        {
            m_TxTime = value;
        }
    }

    private string txtTimeForSerialization
    {
        get
        {
            if (TxTime.HasValue)
            {
                return TxTime.Value.ToString("o");
            }
            else
            {
                return null;
            }
        }
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        //implement reader if needed...
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("name", this.Name);
        writer.WriteAttributeString("txtTime", this.txtTimeForSerialization);
    }
}

      

Implementing IXmlSerializable

, you no longer need to use attributes, and your code for writing to channel.txt will remain the same:



using (FileStream fs = new FileStream("channels.txt", FileMode.Create))
{
    XmlSerializer serializer = new XmlSerializer(typeof(Channel));
    serializer.Serialize(fs, objectName);
}

      

Here's the result:

<?xml version="1.0"?>
<Channel name="NAME" txtTime="2017-03-26T12:57:25.6780078Z" />

      

0


source







All Articles