У меня есть WSDL, который, как ожидает потребитель моего веб-сервиса, будет строго соблюдаться. Я преобразовал его в интерфейс с wsdl.exe, и мой веб-сервис реализовал его. За исключением этой проблемы, я был в целом доволен результатами.
Простой метод GetCurrentTime будет иметь следующий класс ответа, сгенерированный из WSDL в определении интерфейса:
[System.CodeDobmCompiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="[Client Namespace]")]
public partial class GetCurrentTimeResponse {
private System.DateTime timeStampField;
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified]
public System.DateTime TimeStamp{
// [accesses timeStampField]
}
}
Когда я помещаю данные ответа в автоматически сгенерированный класс ответа, они сериализуются в соответствующий XML-ответ. (Большинство веб-методов имеют гораздо более сложные типы возвращаемых данных с несколькими уровнями массивов.)
Проблема в том, что сериализация объектов DateTime по умолчанию нарушает одно из требований WSDL:
...
<xsd:simpleType name="SearchTimeStamp">
<xsd:restriction base="xsd:dateTime">
<xsd:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{1,7})?Z">
</xsd:restriction>
</xsd:simpleType>
...
Обратите внимание на последнюю часть шаблона, где субсекунды должны быть либо 1, либо 7 символами, если они включены. Кажется, что клиент отклоняет ответ, потому что он не соответствует этому требованию.
Основная проблема заключается в том, что, когда .NET сериализует объект DateTime, он пропускает все конечные нули, что означает, что полученное значение в секундах изменяется по длине. (например, «12: 34: 56.700» сериализуется как «<TimeStamp>
12: 34: 56: 7 </TimeStamp>
» по умолчанию). Мы используем точность в миллисекундах, поэтому мне нужно, чтобы все метки времени форматировались с 7 субсекундными цифрами, чтобы соответствовать WSDL.
Было бы легко, если бы я мог указать строку формата, но я не уверен, как управлять строкой, которую объект DateTime использует для сериализации в XML или иным образом переопределить поведение сериализации. Как мне это сделать? Имея в виду следующее ...
- Я хотел бы изменить сгенерированный код как можно меньше ... желательно, не делать этого вообще, если изменение может быть сделано через частичный класс или унаследованный класс.
- Использование унаследованного класса для возвращаемого типа веб-метода приведет к тому, что веб-служба больше не будет реализовывать автоматически сгенерированный интерфейс.
- Тип TimeStamp встречается в других, более сложных типах ответов. Таким образом, ручное переопределение всего процесса сериализации может быть чрезмерно трудоемким.
Обновление:
Я попытался реализовать IXmlSerializable на ранней стадии, как предложил Джон, и получил следующую ошибку:
System.InvalidOperationException: There was an error reflecting type '[...].GetCurrentTimeResponse'. ---> System.InvalidOperationException: Only XmlRoot attribute may be specified for the type [...].GetCurrentTimeResponse. Please use XmlSchemaProviderAttribute to specify schema type.
После этого я решил, что мне придется слишком много взламывать сгенерированный код, и продолжал искать другие решения.