2009-08-12 4 views
17

Podczas tworzenia aplikacji ASP.NET MVC znajduję kilka miejsc, w których moje akcje JsonResult rzucają wyjątek "Podczas serializacji obiektu wykryto cykliczne odniesienie".Jak zapobiec serializacji JSON w ASP.NET MVC?

Na razie usuwam odnośniki, o których mowa, ale najlepiej byłoby po prostu oznaczyć właściwość tak, aby serializator JSON ją ignorował.

Czy ktoś może zasugerować, w jaki sposób mogę to zrobić?

+0

Jakiego serializatora używasz? –

+0

JsonResult to mój typ zwracany, więc zakładam, że jest to serializer, który jest domyślny w klasie kontrolera ASP.NET MVC 1.0. – JMP

+0

Który jest JavaScriptSerializer. – womp

Odpowiedz

28

[ScriptIgnore]powinien pracować dla ciebie.

+2

To powinno działać, ponieważ JsonResult wewnętrznie używa JavaScriptSerializer. – womp

+3

Uwaga dla innych: może być konieczne dodanie odniesienia do zestawu System.Web.Extensions w celu udostępnienia go, przynajmniej w .NET 4. – Jacob

+4

System.Web.Script.Serialization.ScriptIgnore –

13

ja ogólnie okazało się, że dla kompleksu obiektów wszelkich starań, aby tylko szeregować tworząc tymczasowy „Between” obiektu:

na przykład o referencje I wykonaj następujące czynności. Tak naprawdę robię to w codebehind na mojej stronie modelu ASPX.

Spowoduje to utworzenie ładnego obiektu JSON. Zauważysz, że mogę nawet zmienić mój model, a strona nadal będzie działać. To kolejna warstwa abstrakcji między modelem danych a stroną. Nie sądzę, że mój kontroler powinien wiedzieć o JSON tak bardzo, jak to możliwe, ale ASPX "codebehind" z pewnością może.

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

W moim ASPX po prostu zrobić to w bloku:

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); 
    } 
} 

Jestem gotowy na luz przeciwko tej propozycji ... to przyniesie ...

I m nie uzyskuję dostępu do danych, po prostu ponownie formatuję model dla widoku. Jest to logika "widoku modelu", a nie "modelu kontrolera".

+2

+1. Na początku chciałem dać pewien luz: "Nie chcę tworzyć wielu modeli", ale wspominasz o "modelu widoku", który zaczyna mieć dla mnie jakiś sens: tworzysz modele logiki biznesowej, dlaczego nie tworzyć modeli do widoku logika? Znakomity! Nie jest to odpowiedź na moją konkretną sytuację, ale warta przegranej. – JMP

+0

Nie chcę też tworzyć wielu modeli! jest to najprostszy sposób, aby to zrobić bez konieczności tworzenia innej klasy (tutaj niepotrzebne). model powinien być danymi i tylko dane, a nie w jaki sposób dane są wyświetlane i choć nie zawsze jest to praktyczne, zawsze należy minimalizować sprzężenie między widokiem i modelem, przy czym widok zmienia się na inną technologię lub trzeba podać wiele różnych widoków (ajax/flash/plain html) –

+0

Podoba mi się to podejście w przypadku, gdy możesz potrzebować kilku różnych serializacji JSON tego samego bazowego modelu. –

2

Polecam użyć JSON.NET. Umożliwia serializację odwołań cyklicznych i zapewnia znacznie więcej opcji serializacji.

2

Co powiedział Simon. Dodaj małą akcję, aby utrzymać wagę kodu pod kontrolą.

1

Najczystszym podejściem, jakie znalazłem, jest użycie kombinacji [DataContract] w klasie i [DataMember] we właściwościach, które mają zostać przekształcone do postaci szeregowej. Atrybut DataContract informuje różne serializery, aby ignorowały wszelkie właściwości, które nie mają atrybutu DataMember.

Istnieją dwie główne korzyści w porównaniu do używania ScriptIgnoreAttribute. Po pierwsze, nie ma zależności od zestawu System.Web.Extensions. Po drugie, działa z innymi typami serializacji, a nie tylko z JSON. Na przykład, jeśli korzystasz z nowego interfejsu API WWW w MVC 4, podejście DataContract/DataMember będzie również działać z serializatorem XML.

Rozważ scenariusz, w którym twoje obiekty są przechowywane w udostępnianej bibliotece i ponownie użyte w różnych projektach - nie chcesz mieć zależności od System.Web.Extensions, i chcesz luźno opisać zasady serializacji - a nie zachowanie kodu twardego specyficzne dla JSON, XML itp.