Служба XML неправильно и непредсказуемым образом анализирует поле DateTime - PullRequest
1 голос
/ 08 апреля 2011

У меня есть объект со следующим свойством:

[ScriptIgnore]
public DateTime Date
{
    get { return new DateTime(this.Ticks); }
    set { this.Ticks = value.Ticks; }
}

Он задает поле Ticks, которое определяет, как DateTime хранится в базе данных.

Проблема в том, что я вижуXML входит с полем Date, отформатированным следующим образом:

<Date>2011-04-08T12:29:00.000Z</Date>

, которое является прекрасным строковым представлением DateTime.И при тестировании эта строка анализирует DateTime, который вы ожидаете.

Но в системе устанавливается дата 2011-04-10 12:29, или ровно через два дня в будущем.

Это происходит непоследовательно и непредсказуемо.Я могу сделать сотни заявлений, и все они верны.Но когда клиент отправляет их в ранние утренние часы, несколько из них заканчивают с датами два дня в будущем.Это приводит меня к нескольким, в настоящее время не подлежащим рассмотрению, вопросам:

  1. Какой метод конструктора или синтаксического анализа используется, когда XML десериализуется в DateTime?

  2. Клиент находится в центральном времени, наш сервер - по восточному времени (хотя все времена всегда конвертированы в GMT), это как-то влияет?

  3. Что подсказывает тот факт, чтобольшинство ошибок происходят в ранние утренние часы, но не могут быть воспроизведены остальную часть дня, дайте мне, или это просто странное совпадение?

ОБНОВЛЕНИЕ:

После прочтения следующего сообщения в блоге: http://blogs.msdn.com/b/bclteam/archive/2005/03/07/387677.aspx Похоже, что .net DateTime действительно имеет проблемы с десериализацией.И он действительно использует время локального сервера, даже когда не должен.Это не объясняет ВСЕ мои проблемы, но приводит к решению прекратить использование типа DateTime в службах XML, и вместо этого клиент должен вместо этого отправлять datetime в виде тиков.Пока .Net не дает сбой при разборе длинных, у нас должно быть все в порядке.

ОБНОВЛЕНИЕ 2:

Клиент был против отправки datetime в виде тиков, так как каждыйОС имеет другое определение того, что такое Ticks (клиент на Java, не знаю, какая ОС). Поэтому мы решили использовать строки.Клиент вообще не изменил свой отправленный XML, но мы могли бы вручную проанализировать строку до даты вместо того, чтобы позволить десериализатору сделать это.

Я обновил свойство следующим образом:

[ScriptIgnore]
public string Date
{
    get { return new DateTime(this.Ticks).ToString(); }
    set
    {
        if (string.IsNullOrEmpty(value))
        {
            this.Ticks = 0;
        }
        else
        {
                this.Ticks = DateTime.Parse(value).ToUniversalTime().Ticks;
        }
    }
}

И проблема все еще существует, в 1:00 утра этим утром клиент импортировал приблизительно 20 записей, и только 2 из них таинственным образом перенесли дату.Посмотрев на исходный XML как успешно проанализированной даты, так и тех, которые не были проанализированы, я не вижу никакой разницы в формате.

Любая помощь в этой точке очень ценится.

Ответы [ 3 ]

2 голосов
/ 05 мая 2011

Я не встречал подобных проблем, но столкнулся с проблемами, когда информация о часовом поясе теряется из веб-службы SOAP .NET 2.0, когда метод WebService возвращает DateTime, а не объект, который содержит DateTime.

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

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

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


Еще одна мысль - возможно ли, что это могло быбыть проблема параллелизма / многопоточности?Если у вас есть веские доказательства того, что определенное значение было отправлено, а другое значение было получено, то вы пытались убедиться, что полученное значение было отправлено другим клиентом или может быть установлено из другого места в системе?

2 голосов
/ 05 мая 2011

Это определенно странный случай.Пара вещей может изменить результат разбора.

  1. CultureInfo: по умолчанию Parse использует CurrentCulture.Если у вас есть что-то смешное в ваших настройках глобализации, которое вызывает изменение вашей текущей культуры, это может быть затронуто.
  2. Для MSDN: «Метод Parse пытается проанализировать строку с несколькими неявными шаблонами анализа», и если выдобавьте в него шаблоны культур, и вы можете получить беспорядок.

Мои предложения попробовать:

  1. Использовать метод ParseExact вместо Parse и применять формат встрока даты и времени.
  2. Используйте InvariantCulture при разборе даты и времени (если формат даты и времени в вашем приложении универсален, что я предполагаю, поскольку вы храните тики)

На вашемСеттер попробуй это:

if (string.IsNullOrEmpty(value))  
{  
   this.Ticks = 0;  
}  
else  
{  
   CultureInfo provider = CultureInfo.InvariantCulture;  
   var dateTime = DateTime.ParseExact(value, "yyyy-MM-dd hh:mm:ss", provider);  
   this.Ticks = dateTime.ToUniversalTime().Ticks;  
}

Удачи!

Редактировать 1
Что-то еще пришло мне в голову: ThreadSafety.Если вы обращаетесь к отраженному объекту Ticks (в вашем сеттере вы делаете это. Ticks) из нескольких потоков, вы должны сделать это атомарной операцией.

//same setter code except last line...
var oldTicks = this.Ticks;
var newTicks = dateTime.ToUniversalTime().Ticks;  
while(oldTicks != Interlocked.Exchange(ref this.Ticks, newTicks))  
{ //your break code here  }

Sorta:)
Дайте мне знать, если таковые имеютсяэто помогло разгадать тайну.

1 голос
/ 05 мая 2011

Вы можете исправить эти проблемы, заявив, что все перенесенные даты (перемещенные между удаленными системами) на самом деле UTC , например:

public DateTime StartDateUtc
{
...
}

public DateTime EndDateUtc
{
...
}

И вы оставляете ответственность за преобразованиепо местному времени и из него только в код пользовательского интерфейса (или на самые верхние уровни вашего приложения).

Обратите внимание, что вы не можете реально применять это технически , только в соответствии с соглашением / документацией и принятиемверные свойства и методы семантически помечены как UTC.Плохой программист всегда сможет передать локальную дату следующим свойствам:

StartDateUtc = DateTime.UtcNow; // this is correct
StartDateUtc = DateTime.Now; // this is wrong
...