Изменение сериализации даты по умолчанию в WCF

Есть ли способ изменить сериализацию/десериализацию JSON по умолчанию для DateTime в WCF?

В настоящее время DateTime сериализуется в формате /Date(1372252162657+0200)/, и это должно быть хорошо, но я столкнулся с проблемами, когда мой сервер не находится в UTC (который я не могу изменить).

Все данные о дате/времени, которые обрабатываются этой службой, находятся в формате UTC. Все работает, когда сервер находится в UTC. Тем не менее, для промежуточных/промежуточных сред установлено значение GMT ​​+ 1 (Париж), и сериализатор предполагает, что даты/время находятся в GMT + 1, полностью игнорируя атрибут Kind. Так что, как вы ожидали, вызов DateTime.SetKind() и установка его в UTC не будет работать. По сути, сериализованные времена задерживаются на час.

Я могу либо делать двусторонние диалоги даты (это также делает то же самое допущение при десериализации так всегда GMT + 1) разговор дат: от UTC до/от времени сервера, но это утомительно. Поэтому я подумал, что может просто переопределить поведение сериализации по умолчанию.

Ответ 1

Да, это можно сделать, используя концепцию " Message Formatters"

Но форматирование сообщений было бы жестким и не вместимым, чтобы объяснять это при переполнении стека. Вы можете ссылаться на Расширяемость WCF: Форматы сообщений

Если вы не хотите испортить это, тогда доступен взлом.

Задайте тип возврата каждого метода в Stream.

например.

        public Stream GetStaticData()
        {
            var objTobeReturned = something;
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
            return new MemoryStream(Encoding.UTF8.GetBytes(objTobeReturned.ToJson()));
        }

здесь ToJson() - мой собственный метод расширения, который преобразует объект в строку json, используя библиотеку NewtonSoft.

WCF пропустит вывод потока для сериализации и передаст его вашему клиенту, как есть.

Надеюсь, вы получили свой ответ.

Ответ 2

Просто, чтобы развернуть фрагмент кода tdelepine, вот код, который я использовал:

В моей службе WCF JSON у меня было (значение NULL) значение DateTime и я хотел, чтобы моя служба вернула дату в более удобочитаемом формате, поэтому мое приложение iPhone сможет ее интерпретировать.

Вот как выглядел мой JSON после внесения нескольких изменений:

enter image description here

Обратите внимание на поле UpdateDateOriginal, которое по умолчанию является способом, которым WCF записывает DateTimes, и более дружественное UpdateDate поле, которое я создал с помощью приведенного ниже кода.

Мои исходные строки выглядели так:

[DataMember]
public DateTime? UpdateDateOriginal { get; set; }

... и вот строки для создания нового более дружественного значения UpdateDate JSON.

[IgnoreDataMember]
public DateTime? UpdateDate { get; set; }

[DataMember(Name = "UpdateDate")]
private string UpdateDateString { get; set; }

[OnSerializing]
void OnSerializing(StreamingContext context)
{
    if (this.UpdateDate == null)
    this.UpdateDateString = "";
    else
    this.UpdateDateString = this.UpdateDate.Value.ToString("MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

[OnDeserialized]
void OnDeserializing(StreamingContext context)
{
    if (this.UpdateDateString == null)
    this.UpdateDate = null;
    else
    this.UpdateDate = DateTime.ParseExact(this.UpdateDateString, "MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

На самом деле вам может оказаться полезным возвращать значения DateTime в формате ISO8601. Например:

UpdateTime: "2014-08-24T13:02:32",

Для этого просто используйте мой код выше, но измените строку "MMM/dd/yyyy HH:mm" на "s" в обоих местах.

И если ваши значения DateTime хранятся в формате UTC, но вы хотите, чтобы ваши службы WCF возвращали значения в пользовательский локальный часовой пояс, вы можете следовать моим советам здесь:

Получить DateTime в локальном часовом поясе пользователей

Это не жизнь проще, с несколькими простыми примерами!

Ответ 3

вы можете использовать это обходное решение, в определении вашего json-объекта

[IgnoreDataMember]
public DateTime dateObject;

public string dateCustomSerialize
{
 get {
//Custom get
}
set {
//Custom set
}
}

В разделе "Оценка" укажите свою сериализацию формата

Ответ 4

Одним из способов является использование форматирования сообщений для изменения значения по умолчанию DataContractSerializer, как описано в Расширение WCF - Форматы сообщений.

Другой вариант - написать метод расширения, который загружает ваш объект в поток, а затем вы можете применить любой сериализатор, который вы хотите к объекту. См. Принятый ответ Заменить стандартный сериализатор JSON по умолчанию в WCF 4 на JSON.NET для получения подробной информации о том, как это сделать.

Ответ 5

Это не решит вашу проблему с часовыми поясами, но я отправлю ее здесь для других, которые сражаются с WCF, тиками и DateTime.

Если вам не нужны тики, но формат времени, доступный для человека, вы можете сделать это, введя дополнительное свойство string. Тогда это вопрос возиться с DateTime, прежде чем превращать значение в строку.

    [IgnoreDataMember]    // Ignore the original tick date.
    public DateTime LastReminderDate { get { return _lastReminderDate; } set { _lastReminderDate = value; } }
    [DataMember]          // Make sure you have a public or private setter!
    public string LastReminderDateText { get { return _lastReminderDate.ToString(); } set { _lastReminderDate = DateTime.Parse(value); } }