Я работаю над проектом Entity Framework. Я хочу сериализовать кучу экземпляров класса сущностей. Я связал их вместе в класс контейнера:
public class Pseudocontext
{
public List<Widget> widgets;
public List<Thing> things;
Etcetera... это экземпляр этого класса, который я пытаюсь сериализовать. Я хочу, чтобы JSON.NET сериализовал члены каждого экземпляра класса сущности, которые фактически являются столбцами в базовой базе данных. Я не хочу, чтобы он даже пытался сериализовать ссылки на объекты.
В частности, мои классы объектов имеют виртуальные члены, которые позволяют мне писать код С#, который перемещает все мои отношения между сущностями, не беспокоясь о фактических значениях ключа, объединениях и т.д., и я хочу, чтобы JSON.NET игнорировал связанные части моих классов объектов.
На первый взгляд, похоже, есть опция конфигурации JSON.NET, которая делает именно то, о чем я говорю:
JsonSerializer serializer = new JsonSerializer();
serializer.PreserveReferencesHandling = PreserveReferencesHandling.None;
К сожалению, JSON.NET, похоже, игнорирует второе утверждение выше.
Я действительно нашел веб-страницу (http://json.codeplex.com/workitem/24608), где кто-то другой довел эту проблему до сведения самого Джеймса Ньютона-короля, и его ответ (в целом) был "Напишите пользовательский разрешитель контракта".
Как неадекватно, когда я нахожу этот ответ, я пытаюсь следовать его указаниям. Я очень хотел бы написать "контрактный резольвер", который игнорировал бы все, кроме примитивных типов, строк, объектов DateTime и моего собственного класса Pseudocontext, а также содержащихся в нем списков. Если у кого-то есть пример чего-то, что по крайней мере напоминает это, это может быть все, что мне нужно. Это то, что я придумал самостоятельно:
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;
}
}
Когда я пытаюсь использовать вышеизложенное (установив serializer.ContractResolver на экземпляр WhatDecadeIsItAgain до сериализации), я получаю ошибки OutOfMemory во время сериализации, которые указывают на то, что JSON.NET сталкивается с циклами ссылок, которые никогда не заканчиваются (несмотря на мой попытки сделать JSON.NET просто игнорировать ссылки на объекты).
Я чувствую, что мой "пользовательский разрешитель контракта" может быть неправильным. Как показано выше, он строится вокруг предпосылки, что я должен вернуть стандартный "контракт" для типов, которые я хочу сериализовать, и "контракт", который просто возвращает "нуль" для всех других типов.
Я понятия не имею, насколько правильны эти предположения, и это нелегко сказать. Дизайн JSON.NET в значительной степени основан на наследовании реализации, переопределении метода и т.д.; Я не очень похож на OOP, и я считаю, что такой дизайн будет довольно неясным. Если бы был реализован интерфейс "пользовательский контрактный резольвер", Visual Studio 2012 мог бы быстро и быстро завершить требуемые методы, а я представьте, что у меня будет небольшая проблема с заполнением заглушек реальной логикой.
У меня не возникло бы проблемы с написанием, например, метода, который возвращает "true", если я хочу сериализовать объект поставляемого типа и "false" в противном случае. Возможно, мне что-то не хватает, но я не нашел такого метода для переопределения и не смог найти гипотетический интерфейс (ICustomContractResolver?), Который бы сказал мне, что я на самом деле должен делать в последнем фрагменте кода вставленный выше.
Кроме того, я понимаю, что есть атрибуты JSON.NET([JsonIgnore]?), которые предназначены для решения подобных ситуаций. Я не могу использовать этот подход, потому что я использую "модель сначала". Если я не решит разорвать всю архитектуру проекта, мои классы объектов будут автоматически сгенерированы, и они не будут содержать атрибуты JsonIgnore, и я не чувствую себя комфортно, редактируя автоматизированные классы, чтобы содержать эти атрибуты.
Кстати, какое-то время у меня были вещи, созданные для сериализации ссылок на объекты, и я просто игнорировал все лишние данные "$ ref" и "$ id", которые JSON.NET возвращал в свой вывод сериализации. Я отказался от этого подхода на данный момент, по крайней мере, потому что (довольно внезапно) сериализация начала принимать чрезмерное количество времени (~ 45 минут, чтобы получить ~ 5 МБ JSON).
Я не смог связать это внезапное изменение в производительности до того, что я сделал. Во всяком случае, объем данных в моей базе данных ниже, чем тогда, когда сериализация фактически завершалась в разумные сроки. Но я был бы более чем счастлив вернуться к status quo ante (в котором мне просто нужно было игнорировать "$ ref", "$ id" и т.д.), Если бы это было возможно.
На этом этапе я также открыт для перспективы использования какой-либо другой библиотеки JSON или другой стратегии. Я чувствую, что могу просто использовать StringBuilder, System.Reflection и т.д., И придумал свое собственное домашнее решение... но не JSON.NET должен был легко справиться с этим видом?