I have a javascript function that calls an MVC controller with JSON data:
我有一个javascript函数,用JSON数据调用MVC控制器:
var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', { jsonData: specsAsJson });
On the server side, within the controller, I can't seem to get past this error:
在服务器端,在控制器内,我似乎无法通过此错误:
/Date(1347992529530)/ is not a valid value for DateTime.
/ Date(1347992529530)/不是DateTime的有效值。
That exception happens when I call Deserialize() (third line in method below):
当我调用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);
}
I've been doing some googling, and the above code is my latest attempt to make this work (using the TimeSpanJsonConverter from here). Other approaches show sending only a date to the server, but I have a list of objects that have dates as some properties.
我一直在做一些谷歌搜索,上面的代码是我最近尝试使这项工作(从这里使用TimeSpanJsonConverter)。其他方法显示只向服务器发送日期,但我有一个对象列表,其中日期作为一些属性。
Is there an elegant, generally-accepted approach to solving this, or do we still need some kind of ugly work-around? What's the right way to resolve this?
是否有一种优雅的,普遍接受的方法来解决这个问题,还是我们还需要某种丑陋的解决方法?解决这个问题的正确方法是什么?
=================== End of original question ===================
===================原始问题结束===================
Edit - SOLVED by serializing using JsonConvert
编辑 - 通过使用JsonConvert序列化解决
See my answer below (not the crappy work-around in this question).
请参阅下面的答案(不是这个问题中糟糕的解决方法)。
Edit - Crappy work-around
编辑 - 蹩脚的解决方案
I created a DTO with the exact same fields as the domain object, except that I made the date fields strings so they would deserialize. Now that I can deserialize it, I'll work on getting the dates into a valid format so I can create domain objects from my DTOs.
我创建了一个DTO,其字段与域对象完全相同,只是我将日期字段设置为字符串,以便反序列化。现在我可以反序列化它,我将努力将日期转换为有效的格式,以便我可以从我的DTO创建域对象。
public class EquipmentSpecDto
{
public string StartTime { get; set; }
public string EndTime { get; set; }
// more properties here
}
And I simply just used the DTO for the deserialization:
我只是使用DTO进行反序列化:
var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData);
Edit 2 - Converting JavaScript Dates to .NET
编辑2 - 将JavaScript日期转换为.NET
For completeness, and in the hopes that I save someone else an hour, this is how I was able to convert the javascript dates:
为了完整性,并希望我一个小时保存其他人,这就是我能够转换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);
}
5 个解决方案
#1
13
I found a simple answer. In my javascript, I was serializing the data using the JavaScriptSerializer. After much googling, I found this article that shows how to serialize using JsonConvert that causes a more .NET-friendly DateTime to be used.
我找到了一个简单的答案。在我的javascript中,我使用JavaScriptSerializer序列化数据。经过大量的谷歌搜索后,我发现这篇文章展示了如何使用JsonConvert进行序列化,这会导致使用更友好的DateTime。
Old:
旧:
var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))
Dates look like this: Date(1348017917565)
日期看起来像这样:日期(1348017917565)
New:
新:
var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));
Dates look like this: 2012-09-18T21:27:31.1285861-04:00
日期看起来像这样:2012-09-18T21:27:31.1285861-04:00
So the problem was really how I was serializing in the first place. Once I used JsonConvert, deserialization on the back end simply worked.
所以问题实际上是我首先如何序列化。一旦我使用JsonConvert,后端的反序列化就可以了。
#2
6
I found this piece of code on the internet. It worked like a charm for me...
我在互联网上找到了这段代码。它对我来说就像一个魅力......
function customJSONstringify(obj) {
return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/")
}
#3
3
One thing that catches people out quite often with converting between Javascript dates and various server-side languages is that although both sides may be able to understand a unix-style timestamp value, JS uses microsecond-precision timestamp, whereas in most other languages the default timestamp precision is to the second.
通过在Javascript日期和各种服务器端语言之间进行转换,经常捕获人们的一件事是,尽管双方都能够理解unix样式的时间戳值,但JS使用微秒精度时间戳,而在大多数其他语言中,默认值时间戳精度是第二个。
In other words, 1347993132851 in Javascript needs to be divided by 1000 in order to be recognised as a unix timestamp in other languages.
换句话说,Javascript中的1347993132851需要除以1000才能被识别为其他语言的unix时间戳。
Alternatively, if your platform can accept formatted date strings, use the Javascript Date()
object to convert a timestamp value into a formatted date to send to the server. Or even better, use a helper library such as Date.js or Moment.js.
或者,如果您的平台可以接受格式化的日期字符串,请使用Javascript Date()对象将时间戳值转换为格式化日期以发送到服务器。或者甚至更好,使用帮助库,如Date.js或Moment.js。
#4
1
JavaScript (well, EcmaScript) defines its DateTime string interchange format based on a simplification of the ISO-8601 standard.
JavaScript(以及EcmaScript)基于ISO-8601标准的简化定义了其DateTime字符串交换格式。
XML Schema defines its DateTime string interchange format based on ISO-8601 also.
XML Schema也定义了基于ISO-8601的DateTime字符串交换格式。
I have found it handy to use the .NET class System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime
to handle conversion from .NET DateTime values to XML formats and back.
我发现使用.NET类System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime来处理从.NET DateTime值到XML格式的转换以及返回它都很方便。
Since JavaScript is based on the same ISO-8601 standard, perhaps it will work for your JSON case as well.
由于JavaScript基于相同的ISO-8601标准,因此它也可能适用于您的JSON案例。
#5
1
I took @Bob Horn answer but it wasn't working for me. My REST service is using Javascritpt dates. I adapted the referred answer to an extension method.
我接受了@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;
}
}
}
#1
13
I found a simple answer. In my javascript, I was serializing the data using the JavaScriptSerializer. After much googling, I found this article that shows how to serialize using JsonConvert that causes a more .NET-friendly DateTime to be used.
我找到了一个简单的答案。在我的javascript中,我使用JavaScriptSerializer序列化数据。经过大量的谷歌搜索后,我发现这篇文章展示了如何使用JsonConvert进行序列化,这会导致使用更友好的DateTime。
Old:
旧:
var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))
Dates look like this: Date(1348017917565)
日期看起来像这样:日期(1348017917565)
New:
新:
var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));
Dates look like this: 2012-09-18T21:27:31.1285861-04:00
日期看起来像这样:2012-09-18T21:27:31.1285861-04:00
So the problem was really how I was serializing in the first place. Once I used JsonConvert, deserialization on the back end simply worked.
所以问题实际上是我首先如何序列化。一旦我使用JsonConvert,后端的反序列化就可以了。
#2
6
I found this piece of code on the internet. It worked like a charm for me...
我在互联网上找到了这段代码。它对我来说就像一个魅力......
function customJSONstringify(obj) {
return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/")
}
#3
3
One thing that catches people out quite often with converting between Javascript dates and various server-side languages is that although both sides may be able to understand a unix-style timestamp value, JS uses microsecond-precision timestamp, whereas in most other languages the default timestamp precision is to the second.
通过在Javascript日期和各种服务器端语言之间进行转换,经常捕获人们的一件事是,尽管双方都能够理解unix样式的时间戳值,但JS使用微秒精度时间戳,而在大多数其他语言中,默认值时间戳精度是第二个。
In other words, 1347993132851 in Javascript needs to be divided by 1000 in order to be recognised as a unix timestamp in other languages.
换句话说,Javascript中的1347993132851需要除以1000才能被识别为其他语言的unix时间戳。
Alternatively, if your platform can accept formatted date strings, use the Javascript Date()
object to convert a timestamp value into a formatted date to send to the server. Or even better, use a helper library such as Date.js or Moment.js.
或者,如果您的平台可以接受格式化的日期字符串,请使用Javascript Date()对象将时间戳值转换为格式化日期以发送到服务器。或者甚至更好,使用帮助库,如Date.js或Moment.js。
#4
1
JavaScript (well, EcmaScript) defines its DateTime string interchange format based on a simplification of the ISO-8601 standard.
JavaScript(以及EcmaScript)基于ISO-8601标准的简化定义了其DateTime字符串交换格式。
XML Schema defines its DateTime string interchange format based on ISO-8601 also.
XML Schema也定义了基于ISO-8601的DateTime字符串交换格式。
I have found it handy to use the .NET class System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime
to handle conversion from .NET DateTime values to XML formats and back.
我发现使用.NET类System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime来处理从.NET DateTime值到XML格式的转换以及返回它都很方便。
Since JavaScript is based on the same ISO-8601 standard, perhaps it will work for your JSON case as well.
由于JavaScript基于相同的ISO-8601标准,因此它也可能适用于您的JSON案例。
#5
1
I took @Bob Horn answer but it wasn't working for me. My REST service is using Javascritpt dates. I adapted the referred answer to an extension method.
我接受了@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;
}
}
}