2009-11-13 2 views
28

У меня есть повторяющаяся проблема при передаче объектов Serialized между не-NET-клиентами и .NET WCF Services.WCF Отключить чувствительность порядка десериализации

Когда 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 игнорировать порядок полей при десериализации объектов.

ответ

7

Там старая нить на этом здесь:

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

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

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

+3

Интересно. Теперь, чтобы написать перехватчик, который захватывает сообщение, запрашивает мехтод WCF, чтобы выяснить, какой тип ожидался, десериализовать с помощью XmlSerializer (который, согласно потоку, работает), и повторно сериализовать с помощью DataContractSerializer. Как просто;) Тем не менее ... возможно, единственное решение, которое действительно работает так, как ожидалось. Спасибо :) – 2009-11-13 09:47:16

+0

@WillHughes - Я заинтригован, как вы преуспели в своей идее выше? – Reddog

+0

@ Reddog Я никогда не реализовал его - сложно, и он довольно неэффективен (десериализуйте, отразите, повторитециализацию ... просто так, чтобы его можно было десериализовать снова.) Альтернативой было бы заменить сериализатор [, как указано здесь] (http: // weblogs.thinktecture.com/cweyer/2010/12/using-jsonnet-as-a-default-serializer-in-wcf-httpwebrest-vnext.html). – 2012-04-11 23:37:50

12

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

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

+0

А, спасибо за информацию о ''. Я не врывался в генерируемое определение схемы. – 2009-11-13 09:42:43

10

Вы можете использовать свойство 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 ожидает бар и ID элементов в таком порядке (алфавитные, потому что вы не указали явный порядок).

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

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

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

+0

Спасибо - проблема в том, что иногда это допустимо для элементов, которые будут отсутствовать. Ohwell - IsRequired может быть более простым решением, где я могу это сделать. – 2009-11-13 09:44:22

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