我有一个控制器动作,它有效地简单地返回我的模型的 JsonResult。所以,在我的方法中,我有如下内容:
return new JsonResult(myModel);
这很有效,除了一个问题。模型中有一个日期属性,这似乎在 Json 结果中返回,如下所示:
"\/Date(1239018869048)\/"
我应该如何处理日期以便它们以我需要的格式返回?或者我如何在脚本中处理上面的这种格式?
我有一个控制器动作,它有效地简单地返回我的模型的 JsonResult。所以,在我的方法中,我有如下内容:
return new JsonResult(myModel);
这很有效,除了一个问题。模型中有一个日期属性,这似乎在 Json 结果中返回,如下所示:
"\/Date(1239018869048)\/"
我应该如何处理日期以便它们以我需要的格式返回?或者我如何在脚本中处理上面的这种格式?
只是为了扩展casperOne 的答案。
的JSON规范并不考虑日期值。MS 不得不打电话,他们选择的路径是利用 javascript 字符串表示中的一个小技巧:字符串文字“/”与“\/”相同,并且字符串文字永远不会被序列化为“ \/”(甚至“\/”也必须映射到“\\/”)。
请参阅http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2以获得更好的解释(向下滚动到“从 JavaScript 文字到 JSON”)
JSON 的痛点之一是缺少日期/时间文字。许多人在第一次遇到 JSON 时,对了解这一点感到惊讶和失望。没有日期/时间文字的简单解释(安慰与否)是 JavaScript 也从未有过:JavaScript 中对日期和时间值的支持完全通过 Date 对象提供。因此,大多数使用 JSON 作为数据格式的应用程序通常倾向于使用字符串或数字来表示日期和时间值。如果使用字符串,您通常可以期望它采用 ISO 8601 格式。如果使用数字,则该值通常表示自纪元以来世界协调时间 (UTC) 中的毫秒数,其中纪元定义为 1970 年 1 月 1 日午夜 (UTC)。再次,这仅仅是一个约定,而不是 JSON 标准的一部分。如果您要与另一个应用程序交换数据,则需要查看其文档以了解它如何在 JSON 文本中编码日期和时间值。例如,Microsoft 的 ASP.NET AJAX 不使用上述任何一种约定。相反,它将 .NET DateTime 值编码为 JSON 字符串,其中字符串的内容是 /Date(ticks)/ 并且其中 ticks 表示自纪元 (UTC) 以来的毫秒数。所以 1989 年 11 月 29 日凌晨 4:55:30,在 UTC 中被编码为“\/Date(628318530718)\/”。NET AJAX 不使用上述任何一种约定。相反,它将 .NET DateTime 值编码为 JSON 字符串,其中字符串的内容是 /Date(ticks)/ 并且其中 ticks 表示自纪元 (UTC) 以来的毫秒数。所以 1989 年 11 月 29 日凌晨 4:55:30,在 UTC 中被编码为“\/Date(628318530718)\/”。NET AJAX 不使用上述任何一种约定。相反,它将 .NET DateTime 值编码为 JSON 字符串,其中字符串的内容是 /Date(ticks)/ 并且其中 ticks 表示自纪元 (UTC) 以来的毫秒数。所以 1989 年 11 月 29 日凌晨 4:55:30,在 UTC 中被编码为“\/Date(628318530718)\/”。
一种解决方案是将其解析出来:
value = new Date(parseInt(value.replace("/Date(", "").replace(")/",""), 10));
但是我听说在某处有一个设置可以让序列化程序DateTime
使用new Date(xxx)
语法输出对象。我会试着把它挖出来。
的第二个参数JSON.parse()
接受一个reviver
函数,其中规定在返回之前最初产生的值是如何产生的。
这是日期的示例:
var parsed = JSON.parse(data, function(key, value) {
if (typeof value === 'string') {
var d = /\/Date\((\d*)\)\//.exec(value);
return (d) ? new Date(+d[1]) : value;
}
return value;
});
请参阅JSON.parse()的文档
这是我在 Javascript 中的解决方案 - 非常像 JPot 的,但更短(并且可能快一点):
value = new Date(parseInt(value.substr(6)));
“value.substr(6)”取出“/Date(”部分,parseInt函数会忽略最后出现的非数字字符。
编辑:我故意省略了基数(parseInt 的第二个参数);看我下面的评论。另外,请注意 ISO-8601 日期优先于这种旧格式——所以这种格式通常不应该用于新的开发。
对于 ISO-8601 格式的 JSON 日期,只需将字符串传递给 Date 构造函数:
var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
有很多答案可以在客户端处理它,但是如果需要,您可以更改输出服务器端。
有几种方法可以解决这个问题,我将从基础开始。您必须继承 JsonResult 类并覆盖 ExecuteResult 方法。从那里您可以采用几种不同的方法来更改序列化。
方法 1: 默认实现使用JsonScriptSerializer。如果您查看文档,您可以使用 RegisterConverters 方法添加自定义JavaScriptConverters。但这有一些问题:JavaScriptConverter 序列化为字典,即它接受一个对象并序列化为 Json 字典。为了使对象序列化为字符串,它需要一点技巧,请参阅帖子。这个特殊的 hack 也会对字符串进行转义。
public class CustomJsonResult : JsonResult
{
private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// Use your custom JavaScriptConverter subclass here.
serializer.RegisterConverters(new JavascriptConverter[] { new CustomConverter });
response.Write(serializer.Serialize(Data));
}
}
}
方法 2(推荐): 第二种方法是从重写的 JsonResult 开始,然后使用另一个 Json 序列化器,在我的例子中是Json.NET序列化器。这不需要方法 1 的技巧。这是我对 JsonResult 子类的实现:
public class CustomJsonResult : JsonResult
{
private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
// Using Json.NET serializer
var isoConvert = new IsoDateTimeConverter();
isoConvert.DateTimeFormat = _dateFormat;
response.Write(JsonConvert.SerializeObject(Data, isoConvert));
}
}
}
用法示例:
[HttpGet]
public ActionResult Index() {
return new CustomJsonResult { Data = new { users=db.Users.ToList(); } };
}
附加学分: 詹姆斯·牛顿-金
Moment.js 是一个广泛的日期时间库,也支持这一点。http://momentjs.com/docs/#/parsing/asp-net-json-dates/
例如:时刻(“/日期(1198908717056-0700)/”)
它可能会有所帮助。plunker 输出
我发现创建一个新的JsonResult
和返回的结果并不令人满意——不得不用return Json(obj)
with替换所有的调用return new MyJsonResult { Data = obj }
是一种痛苦。
所以我想,为什么不直接劫持JsonResult
使用ActionFilter
:
public class JsonNetFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is JsonResult == false)
{
return;
}
filterContext.Result = new JsonNetResult(
(JsonResult)filterContext.Result);
}
private class JsonNetResult : JsonResult
{
public JsonNetResult(JsonResult jsonResult)
{
this.ContentEncoding = jsonResult.ContentEncoding;
this.ContentType = jsonResult.ContentType;
this.Data = jsonResult.Data;
this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
this.MaxJsonLength = jsonResult.MaxJsonLength;
this.RecursionLimit = jsonResult.RecursionLimit;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var isMethodGet = string.Equals(
context.HttpContext.Request.HttpMethod,
"GET",
StringComparison.OrdinalIgnoreCase);
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& isMethodGet)
{
throw new InvalidOperationException(
"GET not allowed! Change JsonRequestBehavior to AllowGet.");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType)
? "application/json"
: this.ContentType;
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
response.Write(JsonConvert.SerializeObject(this.Data));
}
}
}
}
这可以应用于任何返回 aJsonResult
以使用 JSON.Net 的方法:
[JsonNetFilter]
public ActionResult GetJson()
{
return Json(new { hello = new Date(2015, 03, 09) }, JsonRequestBehavior.AllowGet)
}
这将回应
{"hello":"2015-03-09T00:00:00+00:00"}
如预期的!
如果您不介意is
在每次请求时调用比较,您可以将其添加到您的FilterConfig
:
// ...
filters.Add(new JsonNetFilterAttribute());
并且您的所有 JSON 现在都将使用 JSON.Net 而不是内置的JavaScriptSerializer
.