Правильный способ преобразования даты JSON to.NET DateTime во время десериализации

у меня есть функция javascript, которая вызывает контроллер MVC с данными JSON:

var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', { jsonData: specsAsJson });

на стороне сервера, в контроллере, я не могу пройти мимо этой ошибки:

/ Date (1347992529530)/ не является допустимым значением для DateTime.

это исключение происходит, когда я вызываю Deserialize () (третья строка в методе ниже):

    public ActionResult Save(string jsonData)
    {
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() });
        var specs = serializer.Deserialize<List<EquipmentSpecWithParameterlessConstructor>>(jsonData);

        return View("Index", _allTrackerJobs);
    }

я делал некоторые googling, и приведенный выше код является моей последней попыткой сделать это работа (используя TimeSpanJsonConverter из здесь). Другие подходы показывают отправку только даты на сервер, но у меня есть список объектов, которые имеют даты как некоторые свойства.

существует ли элегантный, общепринятый подход к решению этой проблемы, или нам все еще нужна какая-то уродливая работа? Как правильно решить эту проблему?

=================== конец первоначального вопроса ===================


Edit-решено путем сериализации с помощью JsonConvert

посмотреть мои ответ ниже (не дрянная работа в этом вопросе).


Edit-дерьмовая работа вокруг

Я создал DTO с теми же полями, что и объект домена, за исключением того, что я сделал строки полей даты, чтобы они десериализовались. Теперь, когда я могу десериализовать его, я буду работать над получением даты в допустимом формате, чтобы я мог создавать объекты домена из моих DTOs.

public class EquipmentSpecDto
{
    public string StartTime { get; set; }
    public string EndTime { get; set; }
    // more properties here
}

и я просто использовал DTO для десериализации:

var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData);

Edit 2-преобразование дат JavaScript в .NET

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

    foreach (EquipmentSpecDto specDto in specDtos)
    {
        // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
        // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
        DateTime unixEpoch       = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        Double startMilliseconds = Convert.ToDouble(specDto.StartTime.Substring(6, 13));
        Double endMilliseconds   = Convert.ToDouble(specDto.EndTime.Substring(6, 13));
        DateTime startTime       = unixEpoch.AddMilliseconds(startMilliseconds).ToLocalTime();
        DateTime endTime         = unixEpoch.AddMilliseconds(endMilliseconds).ToLocalTime();
        EquipmentSpec spec       = new EquipmentSpec(startTime, endTime, specDto.Equipment);

        specs.Add(spec);
    }

6 ответов


Я нашел простой ответ. В моем javascript я сериализовал данные с помощью JavaScriptSerializer. После долгого гугления я нашел это статьи это показывает, как сериализовать с помощью JsonConvert, что вызывает более .NET-дружественный DateTime для использования.

старый:

var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))

даты выглядят так: Date(1348017917565)

New:

var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));

даты выглядят так: 2012-09-18T21:27:31.1285861-04:00

Итак, проблема на самом деле, это был мой первый сериал. Как только я использовал JsonConvert, десериализация на задней панели просто работала.


Я нашел этот фрагмент кода в интернете. Для меня это сработало как заклинание...

function customJSONstringify(obj) {
    return JSON.stringify(obj).replace(/\/Date/g, "\\/Date").replace(/\)\//g, "\)\\/")
}

одна вещь, которая ловит людей довольно часто с преобразованием между датами Javascript и различными языками на стороне сервера, заключается в том, что, хотя обе стороны могут понимать значение метки времени в стиле unix, JS использует метку времени с точностью до микросекунды, тогда как в большинстве других языков точность метки времени по умолчанию равна второй.

другими словами, 1347993132851 в Javascript должен быть разделен на 1000, чтобы быть распознанным как метка времени unix в других языки.

кроме того, если ваша платформа может принимать форматированные строки даты, используйте Javascript Date() объект для преобразования значения типа timestamp в формате даты для отправки на сервер. Или даже лучше, используйте вспомогательную библиотеку, такую как дата.js или момент.js.


JavaScript (ну, EcmaScript) определяет свой формат обмена строками DateTime на основе упрощения стандарта ISO-8601.

XML-схема определяет свой формат обмена строками DateTime на основе ISO-8601.

Я нашел удобным использовать класс .NET System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime для обработки преобразования значений .NET DateTime в форматы XML и обратно.

поскольку JavaScript основан на том же стандарте ISO-8601, возможно, он будет работать для вашего случая JSON как что ж.


Я взял ответ @Bob Horn, но он не работал для меня. Мой сервис REST использует даты Javascritpt. Я адаптировал указанный ответ к методу расширения.


using System;

namespace Mediatel.Framework
{
    public static class JsonDate
    {
        public static DateTime ConvertToDateTime(this string jsonDate)
        {
            // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
            // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
            DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            Double milliseconds = Convert.ToDouble(jsonDate);
            DateTime dateTime = unixEpoch.AddMilliseconds(milliseconds).ToLocalTime();

            return dateTime;
        }
    }
}

после receving ошибка

/ Date (1347992529530)/ не является допустимым значением для DateTime.

использование этой замены сработало для меня.

var data = ko.toJSON({ objext: obj});
$.ajax({
    url: "/API/API.asmx/SaveObject",
    type: "POST",
    dataType: "json",
    contentType: "application/json; char-utf8;",
    data: data.replace(/\/Date/g, "\\/Date").replace(/\)\//g, "\)\\/"),
    success: function (r) {},
    error: function (e) {},
    complete: function () {}
});