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