Подтвердить что ты не робот

WCF Отключить чувствительность порядка десериализации

У меня возникает повторяющаяся проблема при передаче Serialized объектов между не-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 будет обрабатывать неправильно расположенные элементы как null.

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

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

4b9b3361

Ответ 1

Здесь есть старый поток:

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

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

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

Ответ 2

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

[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.

Ответ 3

Вы можете использовать свойство 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 не требуется, он просто игнорирует его.

  • Строка идентификатора, указанная ниже, игнорируется, поскольку она находится в неправильном положении.

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