Пропустить [ScriptIgnore] только один раз
Среда для этой ситуации:
Я сталкивался с ситуацией, в которой было бы неплохо включить поле, помеченное как [ScriptIgnore]
, Поле, если оставить его без атрибута, будет представлять собой круговую ссылку и вызовет исключение. Причина в чем-то похожем на это:
public class Foo
{
public int FooId { get; set; }
[ScriptIgnore]
public virtual Collection<Bar> Bars { get; set; }
}
public class Bar
{
public int BarId { get; set; }
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
}
Таким образом, вы можете увидеть здесь, Foo
может иметь много связанных Bars
, И Bar
имеет связанный Foo
,
Вернемся к ситуации. Я загружаю эту ассоциацию в контроллер, используя оператор включения:
.Include( foo => foo.Bars );
Там нет ошибок, потому что включить не влияет [ScriptIgnore]
аннотаций. После отладки ассоциация правильно создается при проверке. Есть список foos
и каждый foo
имеет связанный список Bars
,
Теперь я хочу сериализовать этот построенный список. У меня есть модель представления, которая заполняется данными, это выглядит так:
public class FooView
{
public List<Foo> Foos { get; set; }
public string AsJson()
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(this);
}
}
Поэтому я передаю эту view model в представление и сериализую его:
@model FooView
<script type="text/javascript">
var fooViewModel = @( Html.Raw( Model.AsJson() ) );
</script>
Никаких исключений не выдается, однако, сериализация правильно пропускает поле (Bars
) отмечен [ScriptIgnore]
, на consol.log(fooViewModel)
осмотр ясно, что существует массив Foo
Однако нет связанного массива Bar
в любом из Foos
,
Есть ли способ, которым я могу пропустить это [ScriptIgnore]
пометить только один раз? Я понимаю, что если он пропускается каждый раз, то сериализатор будет сериализовать Foo, посмотреть и увидеть коллекцию типа Bar, сериализовать каждый Bar, заметить, что Bar имеет связанный Foo, сериализовать Foo, заметить, что Foo имеет коллекцию типа Bar...так далее. Я только хочу захватить коллекцию Bar
первый раз. Есть ли способ сделать это? Я понимаю, что он будет пытаться сериализовать Foo
из бара, но он будет пустым. Все это делается с энергичной загрузкой, и весь граф объектов уже построен.
1 ответ
Когда я столкнулся с этим, в итоге я заменил сериализатор на сериализатор Json.NET, который имеет настройки, в частности
_jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
Json.NET будет игнорировать объекты в ссылочных циклах и не сериализует их. При первом обнаружении объекта он будет сериализован как обычно, но если объект будет обнаружен как дочерний объект самого себя, сериализатор пропустит его сериализацию.
Информация для настроек: http://james.newtonking.com/projects/json/help/index.html?topic=html/SerializingJSON.htm и я использовал http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx для замены сериализатора, а затем я добавляю его по умолчанию в global.asax.cs.
configuration.Formatters.Insert(0, new JsonNetFormatter(serializerSettings));
Я понимаю, что это обходной путь (на самом деле не имеет отношения к scriptignore), однако у меня было так много циклических ссылок из предоставленной базы данных, что это казалось лучшим решением в то время.