WCF Отключить чувствительность порядка десериализации - PullRequest
30 голосов
/ 13 ноября 2009

Возникает повторяющаяся проблема при передаче сериализованных объектов между клиентами, не являющимися .NET, и .NET WCF Services.

Когда WCF десериализует объекты, это строго зависит от порядка свойств.

То есть, если я определю свой класс как:

public class Foo 
{ 
  public int ID { get; set; } 
  public int Bar { get; set; } 
} 

Тогда WCF сериализует объект как:

<Foo>
  <Bar>123</Bar>
  <ID>456</ID>
</Foo>

Примечание: свойства сериализуются в алфавитном порядке.

Если вы попытаетесь десериализовать объект, позиции которого поменялись местами Bar и ID, WCF будет рассматривать неправильно расположенные элементы как нулевые.

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

Итак, мой вопрос: можете ли вы сказать десериализатору WCF игнорировать порядок полей при десериализации объектов.

Ответы [ 3 ]

12 голосов
/ 13 ноября 2009

Вы можете указать порядок сериализации, украшая элементы в вашем контракте данных:

[DataContract]
public class Foo 
{ 
  [DataMember(Order=1)]
  public int ID { get; set; } 

  [DataMember(Order=2)]
  public int Bar { get; set; } 
}

Таким образом, вы можете быть уверены, что порядок сериализации всегда одинаков. Но нет никакого способа сказать десериализатору «забыть» о порядке - суть в том, что это обрабатывается с помощью схемы XML и выполняется с использованием элемента <xs:sequence>, что подразумевает и требует порядка. Боюсь, ты не можешь просто отключить это.

На основе этой схемы XML ваши клиенты, не входящие в .NET, должны иметь возможность проверить, соответствует ли их XML, который они собираются отправить, этой схеме - и если это не так, потому что элементы Bar и ID имеют были поменяны местами, они не должны отправлять этот недопустимый XML.

10 голосов
/ 13 ноября 2009

Вы можете использовать свойство IsRequired атрибута DataMember, чтобы указать, что элементы являются обязательными. Таким образом, вместо получения «таинственного» нулевого значения, вы получите более явное сообщение об ошибке, указывающее, что требуемый элемент отсутствует.

[DataContract]
public class Foo 
{ 
  [DataMember(IsRequired=true, Order=1)]
  public int ID { get; set; } 

  [DataMember(IsRequired=true, Order=2)]
  public int Bar { get; set; } 
}

Что происходит в вашем случае:

  • DataContract ожидает элементы Bar и ID в этом порядке (в алфавитном порядке, поскольку вы не указали явный порядок).

  • Встречается элемент ID без предшествующего элемента Bar. Поскольку Bar не требуется, он просто игнорирует его.

  • Элемент ID, следующий за Bar, игнорируется, поскольку он находится в неправильной позиции.

Сказав это, установка IsRequired в значение true поможет только в версии 1 вашего контракта. Элементы, добавленные в последующих версиях, обычно имеют значение IsRequired, равное false. В MSDN есть статья о версии контракта данных .

7 голосов
/ 13 ноября 2009

Здесь есть старая тема:

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/a891928b-d27a-4ef2-83b3-ee407c6b9187

Похоже, что единственный вариант - поменять сериализатор, но затем он становится обязательным, что еще более раздражает.

Редактировать: Вы можете написать свой собственный сериализатор, чтобы переупорядочить элементы, а затем передать его на DataContractSerializer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...