Jak sprawić, aby JSON.NET ignorował relacje między obiektami?

Pracuję nadEntity Framework projekt. Chcę serializować kilka instancji klasy encji. Połączyłem je razem w klasę kontenera:

public class Pseudocontext
{
    public List<Widget> widgets;
    public List<Thing> things;

Etcetera ... to instancja tej klasy, którą próbuję serializować. Chcę, aby JSON.NET serializował członków każdej instancji klasy encji, które są faktycznie kolumnami w bazowej bazie danych. Nie chcę nawet próbować serializować odniesień do obiektów.

W szczególności moje klasy encji mają członków wirtualnych, które pozwalają mi na napisanie kodu C #, który nawiguje wszystkie moje relacje między podmiotami, nie martwiąc się o rzeczywiste wartości kluczy, sprzężenia itp., A ja chcę, aby JSON.NET ignorował powiązane części mojej encji klasy.

Na pierwszy rzut oka wydaje się, że istnieje opcja konfiguracji JSON.NET, która robi dokładnie to, o czym mówię:

JsonSerializer serializer = new JsonSerializer();
serializer.PreserveReferencesHandling = PreserveReferencesHandling.None;

Niestety, JSON.NET wydaje się ignorować drugie stwierdzenie powyżej.

Znalazłem stronę internetową (http://json.codeplex.com/workitem/24608) gdzie ktoś inny zwrócił na siebie uwagę samego Jamesa Newtona-Kinga, a jego odpowiedź (w całości) brzmiała: „Napisz spersonalizowany kontrakt”.

Jako że odpowiedź na to pytanie jest niewystarczająca, starałem się przestrzegać jej wskazówek. Bardzo chciałbym móc napisać „resolvera kontraktowego”, który ignorowałby wszystko oprócz typów pierwotnych, łańcuchów, obiektów DateTime i mojej własnej klasy Pseudokontekstu wraz z listami, które zawiera bezpośrednio. Jeśli ktoś ma przykład czegoś, co przynajmniej przypomina to, może to być wszystko, czego potrzebuję. Oto, co sam wymyśliłem:

public class WhatDecadeIsItAgain : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        JsonContract contract = base.CreateContract(objectType);
        if (objectType.IsPrimitive || objectType == typeof(DateTime) || objectType == typeof(string)
            || objectType == typeof(Pseudocontext) || objectType.Name.Contains("List"))
        {
            contract.Converter = base.CreateContract(objectType).Converter;
        }
        else
        {
            contract.Converter = myDefaultConverter;
        }
        return contract;
    }
    private static GeeThisSureTakesALotOfClassesConverter myDefaultConverter = new GeeThisSureTakesALotOfClassesConverter();
}

public class GeeThisSureTakesALotOfClassesConverter : Newtonsoft.Json.Converters.CustomCreationConverter<object>
{
    public override object Create(Type objectType)
    {
        return null;
    }
}

Kiedy próbuję użyć powyższego (ustawiając serializer.ContractResolver na wystąpienie WhatDecadeIsItAgain przed serializacją), otrzymuję błędy OutOfMemory podczas serializacji, które wskazują, że JSON.NET napotyka pętle odniesienia, które nigdy się nie kończą (pomimo moich wysiłków JSON.NETpo prostu ignoruj ​​odwołania do obiektów).

Czuję, że mój „rozwiązujący kontrakt niestandardowy” może się mylić. Jak pokazano powyżej, opiera się na założeniu, że powinienem zwrócić domyślną „umowę” dla typów, które chcę serializować, oraz „kontrakt”, który po prostu zwraca „null” dla wszystkich innych typów.

Nie mam jednak pojęcia, jak poprawne są te założenia i niełatwo to stwierdzić. Projekt JSON.NET opiera się w dużej mierze na dziedziczeniu implementacji, nadpisywaniu metod itp .; Nie jestem za bardzoOOP facet, i uważam, że ten projekt jest dość niejasny. Czy istniał interfejs „rozpoznawania umów niestandardowych”, który mógłbym wdrożyć,Visual Studio 2012 byłby w stanie bardzo szybko usunąć wymagane metody i wyobrażam sobie, że nie będę miał problemów z wypełnieniem kodu pośredniego prawdziwą logiką.

Nie miałbym problemu z napisaniem, na przykład, metody zwracającej „prawda”, jeśli chcę serializować obiekt podanego typu i „fałsz” w przeciwnym razie. Być może coś mi brakuje, ale nie znalazłem takiej metody do przesłonięcia, ani nie udało mi się znaleźć hipotetycznego interfejsu (ICustomContractResolver?), Który powiedziałby mi, co mam robić w ostatnim fragmencie kodu wstawiony powyżej.

Ponadto zdaję sobie sprawę, że istnieją atrybuty JSON.NET ([JsonIgnore]?), Które są zaprojektowane do radzenia sobie z takimi sytuacjami. Naprawdę nie mogę użyć tego podejścia, ponieważ używam „najpierw model”. Jeśli nie zdecyduję się podrzeć całej mojej architektury projektu, moje klasy encji zostaną automatycznie wygenerowane i nie będą zawierać atrybutów JsonIgnore, ani też nie czuję się komfortowo edytując zautomatyzowane klasy, aby zawierały te atrybuty.

Nawiasem mówiąc, na chwilę jazrobił skonfigurować rzeczy do serializacji odwołań do obiektów, a ja po prostu ignorowałem wszystkie zbędne dane „$ ref” i „$ id”, które JSON.NET zwracał w swoim wyjściu serializacji. Na razie zrezygnowałem z tego podejścia, ponieważ (dość nagle) serializacja zaczęła zajmować nadmierną ilość czasu (~ 45 minut, aby uzyskać ~ 5 MB JSON).

Nie byłem w stanie powiązać tej nagłej zmiany wydajności z czymś szczególnym, co zrobiłem. Jeśli już, ilość danych w mojej bazie danych jest teraz mniejsza niż w przypadku, gdy serializacja faktycznie kończyła się w rozsądnym czasie. Ale byłbym bardziej niż zadowolony z powrotu dostatus quo ante (w którym musiałem po prostu zignorować „$ ref”, „$ id” itp.), jeśli można to osiągnąć.

W tym momencie jestem również otwarty na perspektywę użycia innej biblioteki JSON lub zupełnie innej strategii. Czuję, że mógłbym po prostu użyć StringBuilder, System.Reflection itd. I pochodzić z mojego własnego, domowego rozwiązania ... ale czy JSON.NET nie powinien być w stanie poradzić sobie z tego rodzaju rzeczami dość łatwo?

questionAnswers(3)

yourAnswerToTheQuestion