4

Is there a way to get the ShouldSerialize* pattern working with DataContractSerializer?

Here is a small example:

I have a simple class Person which looks like this:

[DataContract]
public class Person
{
  [DataMember]
  public string FirstName { get; set; }
  public bool ShouldSerializeFirstName()
  {
    return !string.IsNullOrEmpty(FirstName);
  }

  [DataMember]
  public string LastName { get; set; }
  public bool ShouldSerializeLastName()
  {
    return !string.IsNullOrEmpty(LastName);
  }

  public Person(string firstName, string lastName)
  {
    FirstName = firstName;
    LastName = lastName;
  }
  public Person(string firstName)
  {
    FirstName = firstName;
  }
  public Person()
  {
  }
}

FirstName or LastName should only be serialized if they are not null or empty. This works with XmlSerializer but DataContractSerializer seems to ignore the ShouldSerializepattern. The *Specified pattern also doesn't work.

I'm creating two different Xml files. One with DataContractSerializer, one with XmlSerializer:

List<Person> persons = new List<Person>();
persons.Add (new Person("John", "Doe"));
persons.Add (new Person("Carl"));

DataContractSerializer serializer = new DataContractSerializer (typeof (List<Person>));
using (XmlWriter writer = XmlWriter.Create(@"c:\test1.xml", settings))
{
  serializer.WriteObject (writer, persons);
}

XmlSerializer xmlSerializer = new XmlSerializer (typeof (List<Person>));
XmlWriter xmlWriter = XmlWriter.Create (@"c:\text2.xml", settings);
xmlSerializer.Serialize (xmlWriter, persons);
xmlWriter.Close();

The output of the file test1.xml (DataContractSerializer) looks like this:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfPerson xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/XmlSerialization">
  <Person>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
  </Person>
  <Person>
    <FirstName>Carl</FirstName>
    <LastName i:nil="true" />
  </Person>
</ArrayOfPerson>

The output of file test2.xml (XmlSerializer) looks like this:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Person>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
  </Person>
  <Person>
    <FirstName>Carl</FirstName>
  </Person>
</ArrayOfPerson>
M.E.
  • 2,759
  • 3
  • 24
  • 33

2 Answers2

5

AFAIK, ShouldSerialize* does not work with datacontract serializer. It is useless in the Kevin answer. You can remove it. Unfortunatly, the code given only work if you handle null value.

Here is a more generic solution: It returns null value depending of a given condition.

    [DataContract]
    public class Person
    {
      private string firstName;
      [DataMember(IsRequired = false, EmitDefaultValue = false)]
      public string FirstName
      {
        get
        {
            //Put here any condition for serializing
            return string.IsNullOrWhiteSpace(firstName) ? null : firstName;
        }
        set
        {
            firstName = value;
        }
      }
    }
Eric Bole-Feysot
  • 13,949
  • 7
  • 47
  • 53
4

You should set the IsRequired attribute on the DataMember:

[DataContract]
public class Person
{
  [DataMember(IsRequired = False, EmitDefaultValue = False)]
  public string FirstName { get; set; }
  ...
}
Kevin Mangold
  • 1,167
  • 8
  • 21
  • This seems not to work. The properties still get serialized altough they are null. – M.E. Jul 09 '12 at 12:08
  • Add EmitDefaultValue = false, to that list, too (changed in the SSCE, as well). – Kevin Mangold Jul 09 '12 at 12:10
  • 2
    The solution is not exactly equivalent to ShouldSerialize*(). With the latter, I am able to explicitly write the value, even if it is the default and I can suppress values not equal to the default, everything based on some other vaiable during runtime. +1 anyway, as it is helpful (and not your fault that we have such a mess with all those different serialization technologies and concepts, produced by one software vendor). – JensG Jan 03 '14 at 21:41
  • 1
    ShouldSeralize* does not work with DataContractSerializer. This answer is misleading, the ShouldSeralize method is never called. The only reason this "works" is because the logic in `ShouldSerializeFirstName()` is redundant to the functionality provided by the parameters to the DataMember attribute. – User Nov 10 '15 at 17:51