ASP.NET MVC JsonResult 日期格式

IT技术 javascript asp.net-mvc json
2021-01-26 04:05:22

我有一个控制器动作,它有效地简单地返回我的模型的 JsonResult。所以,在我的方法中,我有如下内容:

return new JsonResult(myModel);

这很有效,除了一个问题。模型中有一个日期属性,这似乎在 Json 结果中返回,如下所示:

"\/Date(1239018869048)\/"

我应该如何处理日期以便它们以我需要的格式返回?或者我如何在脚本中处理上面的这种格式?

6个回答

只是为了扩展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()的文档

谢谢,解析会去哪里?
2021-03-12 04:05:22
我发布的代码是 JavaScript。你会把它放在你的客户端代码中。
2021-03-15 04:05:22
@HarshilShah 这是parseInt(). 它告诉函数在基数为 10 的数字系统中提取一个整数。这是一个基数。如果你把8放在那里,它会提取一个八进制数。
2021-03-15 04:05:22
事实上,正则表达式更正确为 replace(/\/Date\((-?\d+)\)\//gi, "$1") 因为日期也可以表示为 -ve 数字
2021-03-27 04:05:22
您可以将 js 缩短为 new Date(parseInt(dateString.replace(/\/Date\((\d+)\)\//gi, "$1")))
2021-04-05 04:05:22

这是我在 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
@JohnZabroski:每条规则都有例外。.NET 日期序列化程序从不返回带前导零的整数,因此我们可以安全地省略基数。
2021-03-12 04:05:22
+1 我采用了您的简单解决方案并将其放入递归函数中。请参见此处:danielsadventure.info/dotnetdatetime
2021-03-14 04:05:22
使用 parseInt 时,您应该始终指定基数。[来源]:developer.mozilla.org/en-US/docs/JavaScript/Reference/...
2021-03-18 04:05:22
我们有几乎同样的事情。我们用于value.substr(6, 13)删除其他非数字字符。但是,如果您这样做,则 1938 年 4 月 26 日之前的所有日期都无效!我们不知道parseInt会忽略非数字字符。谢谢!
2021-03-18 04:05:22
@JohnZabroski——parseIntECMAScript ed 5 (2011)开始,应该忽略前导零
2021-04-05 04:05:22

有很多答案可以在客户端处理它,但是如果需要,您可以更改输出服务器端。

有几种方法可以解决这个问题,我将从基础开始。您必须继承 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(); } };
}

附加学分: 詹姆斯·牛顿-金

货币、身份证号码、电话等其他格式呢?从 ModelMetadata 获取这些格式并使用它们将模型序列化为 Json 不是更好的方法吗?如何 ?
2021-03-19 04:05:22
这是最好的解决方案(Perishable Dave 的回答)。服务器负责提供正确的日期格式。还有一个自定义的 JsonResult 提供了更多的好处和控制。我建议实现一个辅助方法“CustomJson(data)”,它实例化 CustomJsonResult,因为存在“Json(data)”,它用它的数据实例化 JsonResult。
2021-03-27 04:05:22
如果您使用这些方法中的任何一种,则需要进行一次更正 - 第一行应该是: private const string _dateFormat = "yyyy-MM-ddTHH:mm:ss"; 我添加了“T”。
2021-04-07 04:05:22

Moment.js 是一个广泛的日期时间库,也支持这一点。http://momentjs.com/docs/#/parsing/asp-net-json-dates/

例如:时刻(“/日期(1198908717056-0700)/”)

它可能会有所帮助。plunker 输出

首先下载moment.js 文件。添加您的项目而不是使用moment("json_date_string_value").format('appropriate format'); 您可以在 momet.js 页面上看到不同的格式值
2021-03-21 04:05:22

我发现创建一个新的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.

这是唯一一个提供可靠方法(可以设置为全局或粒度)而没有奇怪的内联 javascript 的答案。我可以投票两次吗?
2021-04-09 04:05:22