Сериализация дерева объектов для передачи WCF в Silverlight с использованием IsReference = true

Я использую Silverlight 4, .NET 4.0.

У меня есть объект, определенный в общей библиотеке (совместно используемой моим проектом Silverlight и веб-проектом, в котором размещена служба WCF)

Объект представляет собой древовидную структуру, у которой есть список своих дочерних элементов, а также ссылки на своих родителей и корень.

ie.

class TreeNode
{
  public List<TreeNode> Children {get; set;}
  public TreeNode Root { get; set; }
  public TreeNode Parent { get; set; }
}

Проблема в том, что когда Silverlight пытается взять этот объект и отправить его на сервер, я получаю исключение о циклических ссылках. После некоторого исследования я обнаружил, что мне нужно включить для атрибута IsReference значение true следующим образом:

[DataContract(IsReference = true)]
class TreeNode
{
  public List<TreeNode> Children {get; set;}
  public TreeNode Root { get; set; }
  public TreeNode Parent { get; set; }
}

Проблема в том, что когда я это делаю, моя служба WCF больше не работает, так как не может загрузить необходимую для этого сборку:

«Не удалось загрузить файл или сборку System.Runtime.Serialization, Version = 2.0.5.0»

Это связано с тем, что проект, содержащий класс TreeNode, построен для среды выполнения Silverlight, а не для среды выполнения .NET, и использует System.Runtime.Serialization v2.0.5.0, тогда как веб-проект и служба WCF используют версию v4.0.30319.

Итак, мой вопрос: есть ли способ, которым я могу сериализовать этот объект, сохраняя ссылки, не перемещая всю структуру объекта в другой проект, который строится против стандартной среды выполнения .NET 4.0?

Также стоит отметить, что я пробовал использовать условную компиляцию, например:

#if SILVERLIGHT
[DataContract(IsReference = true)]
#endif

Но это не работает, поскольку это служба WCF должна знать, что она должна сохранять ссылки ...

Очень признателен за любую помощь по этому поводу.


person AlishahNovin    schedule 17.12.2010    source источник


Ответы (1)


Для этого сценария я использовал три варианта:

  1. Прокси
  2. Не делиться сборкой, а делиться кодом.
  3. Ссылка на System.Runtime.Serialization для SL из полного кода .NET и установка для copy local значение true (и, при необходимости, использование шага пост-сборки ILMerge для слияния в сборке System.Runtime.Serialization и интернализации, чтобы предотвратить его использование другими сборками ).

2 - самый простой. Сохраните DataContract с IsReference = true. Создайте еще один проект, ориентированный на .NET (другой - на SL). В проекте .NET добавьте свои файлы в виде связанных файлов. Таким образом, при компиляции SL будет использовать dll System.Runtime.Serialization для SL, а проект .NET будет использовать dll System.Runtime.Serialization для .NET.

1 и 3 позволяют вам продолжать использовать саму DLL.

Вариант 1 работает следующим образом: Удалите атрибут DataContract. Перед сериализацией по сети динамически создайте типы прокси, соответствующие вашим классам, которые вы хотите сериализовать (но добавьте атрибут DataContract с IsReference = true). Вы можете создать эти классы с помощью Reflection.Emit (или другого конструктора динамических типов, например Windsor). Затем используйте что-то вроде AutoMapper, чтобы скопировать ваши данные в типы прокси. Сериализовать / десериализовать прокси-типы.

Вариант 3 работает следующим образом: оставьте свой код в том виде, в котором он есть сейчас (с DataContract и IsReference = true). Установите для System.Runtime.Serialization значение Copy Local. При желании добавьте задачу пост-сборки ILMerge с параметром / internalize, чтобы объединить dll System.Runtime.Serialization с вашей собственной.

person Jeff    schedule 17.12.2010