É muito comum haver situações onde retornamos um array de objetos para o cliente. Cada elemento deste array poderá conter instancias de objetos que possuem propriedades que referenciam outros objetos ou até mesmo referencia circulares. Imagine a seguinte situação:
[DataContract]
public class Gerente
{
[DataMember]
public string Nome { get; set; }
}
[DataContract]
public class Empregado
{
[DataMember]
public string Nome { get; set; }
[DataMember]
public Gerente Gerente { get; set; }
}
Note que a classe Empregado possui uma propriedade que aceita uma instancia da classe Gerente. Na implementação do serviço, é perfeitamente possível que exista um mesmo gerente para vários empregados, fazendo com que uma mesma instancia da classe Gerente seja reutilizada por várias instancias da classe Empregado. O código abaixo ilustra isso:
List<Empregado> list = new List<Empregado>();
Gerente g = new Gerente() { Nome = “Bill Buchanan” };
list.Add(new Empregado() { Gerente = g, Nome = “Jack Bauer” });
list.Add(new Empregado() { Gerente = g, Nome = “Chloe O’brien” });
list.Add(new Empregado() { Gerente = g, Nome = “Michelle Dessler” });
Utilizando a configuração padrão do WCF, a instancia da classe Gerente será serializada para cada instancia da classe Empregado, aumentando consideravelmente o tamanho, ainda mais se o objeto conter várias propriedades. Esse comportamento é semelhante ao que conhecemos como by-value e, podemos notar isso a partir do resultado desta serialização:
<ArrayOfEmpregado …=””>
<Empregado>
<Gerente>
<Nome>Bill Buchanan</Nome>
</Gerente>
<Nome>Jack Bauer</Nome>
</Empregado>
<Empregado>
<Gerente>
<Nome>Bill Buchanan</Nome>
</Gerente>
<Nome>Chloe O’brien</Nome>
</Empregado>
<Empregado>
<Gerente>
<Nome>Bill Buchanan</Nome>
</Gerente>
<Nome>Michele</Nome>
</Empregado>
</ArrayOfEmpregado>
A versão 3.5 do .NET Framework trouxe uma nova propriedade para a classe DataContractAttribute: IsReference. Essa propriedade recebe um valor boleano que, por padrão é False, indicando se possíveis referencias de objetos devem ser mantidas na geração do envelope SOAP. Com isso, podemos configurar a classe Gerente como:
[DataContract(IsReference = true)]
public class Gerente
{
[DataMember]
public string Nome { get; set; }
}
Ao executar o mesmo código acima, o resultado passa a ser o seguinte:
<ArrayOfEmpregado
xmlns=”…”
xmlns:i=”…”>
<Empregado>
<Gerente z:Id=”i1″ xmlns:z=”…”>
<Nome>Bill Buchanan</Nome>
</Gerente>
<Nome>Jack Bauer</Nome>
</Empregado>
<Empregado>
<Gerente z:Ref=”i1″ xmlns:z=”…”/>
<Nome>Chloe O’brien</Nome>
</Empregado>
<Empregado>
<Gerente z:Ref=”i1″ xmlns:z=”…”/>
<Nome>Michele</Nome>
</Empregado>
</ArrayOfEmpregado>
Note que não há mais replicação do objeto Gerente. A instancia da classe Gerente será serializada no primeiro empregado e, a partir daí, todos os empregados que utilizarem a mesma instancia apenas a referenciam.