[DICA] Resolvendo o problema “A circular reference was detected while serializing an object of type ‘System.Data.Entity.DynamicProxies”

Recentemente, ao trabalhar em um projeto ASP.NET MVC 4 que solicitava informações serializadas em format JSON de forma assíncrona via GET ($.getJSON) de classes EF POCO, me deparei com a seguinte mensagem de erro:

A circular reference was detected while serializing an object of type ‘System.Data.Entity.DynamicProxies…

Após realizar uma pesquisa demorada no conteúdo disponível online na biblioteca do MSDN e em alguns fóruns (principalmente o Stack Overflow), pude encontrar dois caminhos para solucionar este problema. Testei ambos e optei por utilizar o segundo em meu projeto (por achar mais elegante) e pude comprovar que funcionou de forma plenamente satisfatória. Logo, no primeiro dia do ano (2013), gostaria de compartilhá-la com vocês.

O problema

Em linhas gerais, o erro mencionado anteriormente ocorre quando existem múltiplas dependências entre as classes POCO. Ao solicitar a “serialização”, o ORM (neste caso, o Entity Framework) tenta serializar todas as classes onde o relacionamento existe. Não é preciso dizer que este é um problema evidente, certo? Performance, segurança, etc., podem ser comprometidas com este tipo de operação. Por este motivo, o EF gera o erro e bloqueia a operação,. Cool, não?!

A Figura 1 apresenta o problema de forma gráfica.

classes-poco

Figura 1. As múltiplas dependencias entre as classes POCO

Vamos as soluções!

Solução 1: RegisterConverter personalizado

A primeira solução é escrever um “conversor de registro personalizado” utilizando o método “RegisterConverters” da classe “JavaScriptSerializer”. Neste caso, basta  escrever um conversor personalizado que especifica todas as propriedades (exceto a propriedade mãe) adicionado-o em uma classe parcial, por exemplo, ou na mesma classe de execução do código principal, conforme apresenta o exemplo da Listagem 1.

JavaScriptSerializer serializer;
protected void Page_Load(object sender, EventArgs e)
{
serializer = new JavaScriptSerializer();

// Register the custom converter.
serializer.RegisterConverters(new JavaScriptConverter[] {
new System.Web.Script.Serialization.CS.ListItemCollectionConverter() });
this.SetFocus(TextBox1);
}

Listagem 1. Registrando o conversor personalizado (Fonte: MSDN)

 Você pode visualizar a informação completa sobre a classe “JavaScriptSerializer” seguindo este link.

Solução 2: Serializar uma classe DTO

Simples: não serializar as classes POCO EF, mas sim, serializar um DTO (Data Transfer Object – Saiba mais sobre DTO aqui).Em outras palavras, utilize o conceito de ViewModel. Pessoalmente, não vejo problemas nesta abordagem e até penso ser “elegante”. Um exemplo do que fiz em meu projeto, pode ser visualizado nas Listagens 2 e 3.

var QueryEstados = from e in Contexto.tbEstados
where e.IDPais == _IDPais
orderby e.NomeEstado ascending
select new InfoEstados
{
IDEstado = e.IDEstado,
NomeEstado = e.NomeEstado
};

Listagem 2. Uma consulta Linq simples que instancia uma classe DTO

public class InfoEstados
{
public int IDEstado { get; set; }
public string NomeEstado { get; set; }
}

Listagem 3. A classe DTO de Estados

Bom pessoal, espero que tenha sido útil. Dúvidas ou comentários sobre o conteúdo, por favor, deixem seu comntários ou entre em contato através do formulário de contato do site. Abraços e feliz 2013!

468 ad

2 Comentários

  1. Animal a explicação. Acertou na mosca o que precisava. Eu até tinha pensado nisso mas não tinha implementado. Valeu :)

  2. Ola, boa tarde !!
    Muito bom !!! Outra solução, caso este erro dê na serialização dos objetos, é colocar o atributo [ScriptIgnore] (contido em System.Web.Script.Serialization) na propriedade que esta gerando a referência circular. Este atributo faz com que a propriedade seja ignorada na serialização, não gerando o erro de referência circular…
    Até mais !! :)

Deixe um comentário

O seu endereço de email não será publicado Campos obrigatórios são marcados *


4 × = trinta dois

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>