views:

366

answers:

1

I'm in the process of writing a WCF application which will be consumed by a Silverlight application. I have done most of the design work and I am now doing the implementation, which has made me come up with this question.

Here's an example of something that exists in my application:

[DataContract]
class Person
{
    [DataMember]
    private Towel mostRecentlyUsedTowel;

    [DataMember]
    private Gym gym; //the gym that this person attends

    ...
}

[DataContract]
class Gym
{
    [DataMember]
    private List<Towel> towels; //all the towels this gym owns

    ...
}

Here's what I'm getting at: In my application mostRecentlyUsedTowel will be pointing at something in the towels list for the person's gym. Some of my requests will serialize a Person object.

Is the DataContractSerializer smart enough to notice its being asked to serialize the exact same instance of an object twice? If so, how does it deal with it?

If it will just go about serializing the same instance twice, how should I deal with this so I'm not sending unnecessary data over the link?

+6  A: 

The following code:

[TestMethod]
public void CanSerializePerson()
{
    var towel1 = new Towel() { Id = 1 };
    var towel2 = new Towel() { Id = 2 };
    var towel3 = new Towel() { Id = 3 };
    var gym = new Gym();
    gym.towels.Add(towel1);
    gym.towels.Add(towel2);
    gym.towels.Add(towel3);

    var person = new Person()
    {
      recentlyUsedTowel = towel1,
      gym = gym
    };

    var sb = new StringBuilder();
    using (var writer = XmlWriter.Create(sb))
    {
        var ser = new DataContractSerializer(typeof (Person));
        ser.WriteObject(writer, person);
    }

    throw new Exception(sb.ToString());
}

public class Person
{
    public Towel recentlyUsedTowel { get; set; }
    public Gym gym { get; set; }
}

public class Gym
{
    public Gym()
    {
        towels = new List<Towel>();
    }

    public List<Towel> towels { get; set; }
}


public class Towel
{
    public int Id { get; set; }
}

will evaluate to:

<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org"&gt;
  <gym>
    <towels>
      <Towel><Id>1</Id></Towel>
      <Towel><Id>2</Id></Towel>
      <Towel><Id>3</Id></Towel>
    </towels>
  </gym>
  <recentlyUsedTowel><Id>1</Id></recentlyUsedTowel>
</Person>

If you added the IsReference property to the DataContract attribute of the Towel class like this:

[DataContract(IsReference=true)]
public class Towel
{
    // you have to specify a [DataMember] in this because you are 
    // explicitly adding DataContract
    [DataMember]
    public int Id { get; set; }
}

you would get an output like this:

<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org"&gt;
  <gym>
    <towels>
      <Towel z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"&gt;
        <Id>1</Id>
      </Towel>
      <Towel z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"&gt;
        <Id>2</Id>
      </Towel>
      <Towel z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"&gt;
        <Id>3</Id>
      </Towel>
    </towels>
  </gym>
  <recentlyUsedTowel z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
</Person>

Hope this Helps.

bendewey
That's exactly what I was looking for. Thank-you very much.
Craig