2010-02-21 2 views
20

У меня есть метод службы WCF, который ожидает объект, а затем возвращает его свойства с помощью отражения.Передача экземпляра анонимного типа по WCF

На стороне клиента я создаю анонимный тип объекта

var obj = new {FirstName="John", LastName="Doe"} 

и передать его методу. Я получаю исключение:

Type '<>f__AnonymousType0`2[System.String,System.String]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all 
of its members you want serialized with the DataMemberAttribute attribute. 
See the Microsoft .NET Framework documentation for other supported types. 

Я не могу отметить тип или его членов с сериализации атрибуты, потому что на самом деле нет ни тип свойства явно объявлены. Есть ли способ преодолеть эту проблему?

ответ

17

Не делайте этого.

Это попытка быть умной. Не. Просто объявите нужный тип данных и используйте его. Если вам нужен более свободный тип данных, просто используйте сопоставление значений ключей.

Вам потребуется 5 минут, чтобы написать что-нибудь, что может справиться с этим навсегда. Использование любой такой техники будет стоить вам часов отладки в будущем в будущем.

+0

Yup, я закончил тем, что прохожу словарь ключей-объектов – Andrey

+0

У меня была такая же проблема и прошло полдня, прежде чем я понял, что это плохая идея. Не мой лучший час. Я просто хотел поддержать кёрю с анекдотом того, что он пророчествовал. – Four

1

У вас уже есть ответ. Это невозможно.

Фактически вы не можете передать экземпляр анонимного типа от одного метода другому в пределах вашей программы. Вы, конечно же, не можете передать им между программами.

+0

Фактически, вы можете - вы можете определить тип возврата «объект», а затем просто вернуть свой экземпляр анонимного типа. Это анонимный тип, но он все же в конечном счете сходит с «объекта». Не рекомендуется и не рекомендуется - но это возможно - по крайней мере в .NET. –

+0

@marc_s: Это будет скомпилировано, но будет практически бесполезным, поскольку метаданные не будут созданы для возвращаемого типа 'System.Object'. – Aaronaught

+0

@Aaronaught: Я никогда не говорил, что это было полезно в любом случае, форме или форме - просто возможно :-) Я бы никогда не делал этого сам, но это технически возможно –

2

Нет, нет. Хотя есть методы и методы для возврата объектов анонимного типа из метода, вы не можете отправлять их через WCF.

WCF должен знать все его конкретные типы, которые будут отправляться через, так как вы на самом деле не просто вызываете метод .NET. Вместо этого вызов сообщения преобразуется в сериализованное сообщение, и поэтому любая «вещь», передаваемая по вызову WCF , должна быть сериализована - никаких исключений.

19

answers suggesting что вы can't use an anonymous type over WCF ошибаетесь.

Если вы используете по умолчанию DataContractSerializer для сериализации ваших типов на канале, то да, ответы верны. Это происходит потому, что DataContractSerializer поддерживает следующие сценарии:

  1. Типы сериализованы с помощью Serializable attribute
  2. Типов Сериализированного с использованием XML Serialization
  3. Типы сериализовать с помощью DataContract attribute
  4. Plain-Old-C#-Object (POCO) Serialization

Соответственно, они не с анонимными типами из-за следующего:

  1. Вы не можете применять атрибуты к анонимным типам.
  2. Для XML-сериализации требуется конструктор без параметров без параметров, которого нет у анонимных типов.
  3. То же, что 1.
  4. То же 2.

Однако, вы не обязаны использовать DataContractSerializer сериализовать сообщения в WCF. Вы можете создать custom message formatter, который вы можете использовать для выполнения сериализации самостоятельно.

У вас возникли проблемы, если типы, отправляемые вами в качестве запросов, являются анонимными. Когда вы вернете результаты, у него будет определенное имя в пространстве имен (не в смысле .NET, а в смысле SOA), и вам придется обрабатывать отображение этого конкретного типа обратно на анонимный тип , Однако, поскольку у вас нет доступа к фактическому анонимному типу или способам его создания в коде (по крайней мере динамическим способом), у вас нет выбора, кроме как передать его как объект, если он передан вам, что делает его вроде бесполезным, поскольку каждый должен будет использовать плохие практики, такие как динамические (не плохая практика сама по себе, а обойти эти ограничения в этом случае - да) или cast-by-example.

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

+2

+1 для технически правильного ответа. -1 для упоминания техники, которая является чистым злом. Я волнуюсь, кто-то прочитает это и проигнорирует предупреждение «плохих практик» - забудьте рефакторинг, вам нужен экзорцист. – Aaronaught

+5

Упоминание ЛЮБОЙ метод следует рассматривать как обмен знаниями, а не презрение. Кроме того, даже экзорцисты должны знать о демонах. –

0

Как уже говорилось, объекты должны быть десериализуемыми, и поэтому вам необходимо будет определить структуру заранее. Однако вы можете использовать наследование для определения их и, следовательно, снизить боль. WCF предоставляет атрибут KnownType, чтобы позволить операции службы получать объект базового класса и десериализовать его в объект производного класса. Таким образом, у вас будет только одна (или несколько) служебных операций, которая может обрабатывать все ваши сценарии.

4

Вы можете сериализовать объект в строку JSON и отправить его через WCF, например, так:

//in WCF Server 
dynamic mysentclass = new { FirstName = "John", LastName = "Doe" }; 
string jsonstring = JsonConvert.SerializeObject(mysentclass, Newtonsoft.Json.Formatting.Indented); 
//send the string through WCF 

//in WCF client 
dynamic myreceivedclass = JsonConvert.DeserializeObject<dynamic>(jsonstring); 
MessageBox.Show(myreceivedclass.FirstName.ToString() + " " + myreceivedclass.LastName.ToString()); 

В примере используется Json.NET, который можно получить здесь:

http://www.nuget.org/packages/Newtonsoft.Json/

Вы также можете использовать System.Web.Script.Serialization.JavaScriptSerializer (в System.Web.Extensions.dll), который не такой мощный, как Json.Net, но этого достаточно для простых объектов.

Смежные вопросы