2009-08-12 8 views
17

Al desarrollar una aplicación ASP.NET MVC, estoy encontrando algunos lugares donde mis acciones JsonResult lanzan una excepción "Se detectó una referencia circular al serializar un objeto".¿Cómo evito la serialización JSON en ASP.NET MVC?

Por ahora, estoy eliminando las referencias en cuestión, pero idealmente me gustaría simplemente marcar la propiedad de manera que el serializador JSON lo ignore.

¿Alguien puede sugerir cómo podría hacer esto?

+0

¿Qué serializador estás usando? –

+0

JsonResult es mi tipo de devolución, así que supongo que el serializador es el predeterminado en la clase de controlador de ASP.NET MVC 1.0. – JMP

+0

¿Cuál es el JavaScriptSerializer? – womp

Respuesta

28

[ScriptIgnore]debe trabajo para usted.

+2

Esto debería funcionar porque un JsonResult usa el JavaScriptSerializer internamente. – womp

+3

Nota para otros: es posible que deba agregar una referencia al ensamblaje System.Web.Extensions para que esté disponible, al menos en .NET 4. – Jacob

+4

System.Web.Script.Serialization.ScriptIgnore –

13

He encontrado que por lo general para el complejo de objetos a su alcance para serializar simplemente mediante la creación de un objeto temporal 'entre medio':

Por ejemplo, para testimonios que hacer lo siguiente. De hecho, hago esto en el código subyacente para mi página de modelo ASPX.

Esto crea un buen objeto JSON. Notarás que incluso puedo refacturar mi modelo y la página seguirá funcionando. Es solo otra capa de abstracción entre el modelo de datos y la página. No creo que mi controlador deba saber sobre JSON tanto como sea posible, pero el 'código subyacente' de ASPX ciertamente puede.

/// <summary> 
/// Get JSON for testimonials 
/// </summary> 
public string TestimonialsJSON 
{ 
    get 
    { 
     return Model.Testimonials.Select(
      x => new 
      { 
       testimonial = x.TestimonialText, 
       name = x.name 
      } 
      ).ToJSON(); 
    } 
} 

En mi ASPX acabo de hacer esto en un bloque:

var testimonials = <%= TestimonialsJSON %>; 

// oh and ToJSON() is an extension method 
public static class ObjectExtensions 
{ 
    public static string ToJSON(this Object obj) 
    { 
     return new JavaScriptSerializer().Serialize(obj); 
    } 
} 

Estoy listo para la reacción en contra de esta sugerencia ... lo trae en ...

I' no estoy accediendo a los datos, simplemente reformateando un modelo para la Vista. Esta es lógica de "ver modelo", no lógica de "modelo de controlador".

+2

+1. Al principio, quería ofrecer una reacción violenta "No quiero crear varios modelos", pero mencionas "ver modelo", que empieza a tener sentido para mí: haces modelos para la lógica de negocios, ¿por qué no haces modelos para verlos? ¿lógica? ¡Brillante! No es la respuesta a mi situación específica, pero definitivamente vale la pena un voto positivo. – JMP

+0

¡yo tampoco quiero crear varios modelos! esta es la forma más fácil de hacerlo sin tener que crear otra clase (innecesario aquí). el modelo debe ser la información y solo los datos, no cómo se muestran esos datos y, aunque no siempre es práctico, siempre debe minimizar el acoplamiento entre la vista y el modelo en caso de que la vista cambie a una tecnología diferente o necesite proporcionar múltiples vistas diferentes (ajax/flash/plain html) –

+0

Me gusta este enfoque en caso de que necesite algunas serializaciones JSON diferentes del mismo modelo subyacente. –

2

Aconsejaría usar JSON.NET. Permite serializar referencias circulares y proporciona muchas más opciones de serialización.

2

Lo que dijo Simon. Agregue un poco de acción AutoMapper para mantener el peso del código bajo control.

1

El enfoque más limpio que he encontrado es utilizar una combinación de [DataContract] en la clase y [DataMember] en las propiedades que desea serializar. El atributo DataContract le dice a los diversos serializadores que ignoren cualquier propiedad que no tenga el atributo DataMember.

Existen dos ventajas principales en comparación con el uso de ScriptIgnoreAttribute. Primero, no tiene una dependencia en el ensamblado System.Web.Extensions. En segundo lugar, funciona con otros tipos de serialización, no solo con JSON. Por ejemplo, si está utilizando la nueva API web en MVC 4, el enfoque DataContract/DataMember también funcionará con el serializador XML.

Considere el escenario en el que sus entidades se almacenan en una biblioteca compartida y se reutilizan en varios proyectos; no desea una dependencia de System.Web.Extensions, y desea describir las reglas de serialización, no el comportamiento de código duro específico de JSON, XML, etc.

Cuestiones relacionadas