Изменение сериализации даты по умолчанию в 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); } }