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.
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.
[csharp]
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);
}
[/csharp]
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.
[csharp]
var QueryEstados = from e in Contexto.tbEstados
where e.IDPais == _IDPais
orderby e.NomeEstado ascending
select new InfoEstados
{
IDEstado = e.IDEstado,
NomeEstado = e.NomeEstado
};
[/csharp]
Listagem 2. Uma consulta Linq simples que instancia uma classe DTO
[csharp]
public class InfoEstados
{
public int IDEstado { get; set; }
public string NomeEstado { get; set; }
}
[/csharp]
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!
Facebook
Twitter
Instagram
LinkedIn
RSS