Как переопределить сериализацию C # DateTime классом, автоматически сгенерированным из wsdl? - PullRequest
1 голос
/ 21 апреля 2010

У меня есть 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. После этого я решил, что мне придется слишком много взламывать сгенерированный код, и продолжал искать другие решения.

Ответы [ 3 ]

1 голос
/ 04 октября 2011

Возможно, не самый релевантный ответ на ваш первоначальный вопрос, но, поскольку я был перенаправлен на эту страницу, когда искал способ управления форматированием свойств DateTime в сериализации, кто-то другой может найти это полезным.

Я обнаружил, что, добавив следующее в ваш app.config / web.config, указывает сериализации .NET на последовательное форматирование свойств DateTime:

  <system.xml.serialization>
    <dateTimeSerialization mode="Local" />
  </system.xml.serialization>

Ссылка: http://msdn.microsoft.com/en-us/library/ms229751(v=VS.85).aspx

1 голос
/ 21 апреля 2010

Я никогда не видел, чтобы XML-схема в WSDL накладывала ограничение на xsd:dateTime.

Я полагаю, вам придется реализовать IXmlSerializable в вашем GetCurrentTimeResponse классе. Вы можете сделать это из-за функции «частичного класса» в C #. Создайте другой файл в своем проекте и добавьте следующий код:

public partial class GetCurrentTimeResponse : 
    System.Xml.Serialization.IXmlSerializable
{
    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader) {
        // Fill the TimeStamp property here
    }

    public void WriteXml(XmlWriter writer) {
        // Write out TimeStamp.ToString(
        //    System.Globalization.CultureInfo.InvariantCulture, 
        //    "proper format");
    }
}
0 голосов
/ 21 апреля 2010

Я дебил!

Во-первых, регулярное выражение означает «от 1 до 7 цифр», а не «1 или 7 цифр», хотя в мою защиту Интернет был неправильным. Причина, по которой ответ не был подтвержден, заключалась в том, что в конце отсутствовала буква «Z», указывающая UTC.

Решение было так просто:

GetCurrentTimeResponse response = new GetCurrentTimeResponse() {
    TimeStamp = timeStampWeWant.ToUniversalTime()
}

И это сработало само!

<TimeStamp>2010-04-20T20:12:16.674Z</TimeStamp>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...