MVC 4单页应用程序和日期时间

Bri*_*ord 8 datetime asp.net-mvc-4 asp.net-web-api asp.net-spa

在使用MVC 4的新单页应用程序工具时,我注意到我找到的所有示例都没有包含通过WebApi更新的DateTime示例.我很快发现了原因.

我首先从提供的模板生成标准SPA.然后我打开了TodoItem.cs并添加了DateTime字段.然后我按照评论的指示生成了控制器.(没有datetime字段,一切正常).

生成所有内容后,我启动了应用程序并导航到控制器索引(我称之为控制器"任务").我按预期获得了0个记录的网格页面并单击了添加按钮.我按预期被带到了编辑页面并输入了一些数据,包括我闪亮的新日期时间字段中的日期.然后点击保存.

产生了一个错误:

服务器错误:HTTP状态代码:500,消息:反序列化System.Web.Http.Data.ChangeSetEntry []类型的对象时出错.DateTime内容'01/01/2012'不以'/ Date('和以')/'结尾,如JSON所要求的那样.

看起来工具还不支持DateTime.我确信我可以花一些时间来搞清楚并让它发挥作用,但我想我可能会在这里找到一些运气,因为已经解决了这个问题且可以提供洞察力的人.

有人已经在争吵吗?

更新:我提出了自问这个以来我发现的更多信息.我尝试使用JSON.Net作为我的Formatter,如下所示.我认为这将是最终的解决方案,但是,正如下面推荐的海报还不够.

使用JSON.Net序列化程序时,我收到以下错误:

此DataController不支持实体'JObject'的操作'Update'.

原因是JSON.Net没有完全填充格式化程序试图取消规划的对象(System.Web.Http.Data.ChangeSet).

发送的json是:

[{"Id":"0",
  "Operation":2,
  "Entity":
    {"__type":"TodoItem:#SPADateProblem.Models",
     "CreatedDate":"/Date(1325397600000-0600)/",
     "IsDone":false,
     "Title":"Blah",
     "TodoItemId":1},
  "OriginalEntity":
    {"__type":"TodoItem:#SPADateProblem.Models",
     "CreatedDate":"/Date(1325397600000-0600)/",
     "IsDone":false,
     "Title":"Blah",
     "TodoItemId":1}
}]
Run Code Online (Sandbox Code Playgroud)

内置的Json Formatter能够将此Json重构为ChangeSet对象,并在Entity和OriginalEntity字段中嵌入TodoItem对象.

有没有人得到JSON.Net来正确反序列化?

Jam*_*ter 3

问题是,在当前的测试版中,ASP.NET Web API 使用 .NET DataContractJsonSerializer,它在 .NET 序列化方面存在众所周知的问题DateTime这是最近在 Microsoft Connect 上针对该问题提出的一个安静的错误;MS 回应称,他们已经有一个错误跟踪该问题,但不会在 .Net 4.5/VS11 时间范围内修复。

幸运的是,您可以替换其他 JSON 序列化器,例如James Newton-King出色的JSON.Net

ASP.NET 团队的 Henrik Nielsen 有一篇出色的博客文章,展示了如何将 JSON.Net 与 ASP.NET Web API 结合使用。这是他使用 JSON.Net 的实现MediaTypeFormatter(它还需要连接到 ASP.NET Web API 配置,Henrik 的博客也演示了这一点)。

public class JsonNetFormatter : MediaTypeFormatter
{
    private readonly JsonSerializerSettings settings;

    public JsonNetFormatter(JsonSerializerSettings settings = null)
    {
        this.settings = settings ?? new JsonSerializerSettings();

        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
        Encoding = new UTF8Encoding(false, true);
    }

    protected override bool CanReadType(Type type)
    {
        return type != typeof(IKeyValueModel);
    }

    protected override bool CanWriteType(Type type)
    {
        return true;
    }

    protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext)
    {
        var ser = JsonSerializer.Create(settings);

        return Task.Factory.StartNew(() => {
            using (var strdr = new StreamReader(stream))
            using (var jtr = new JsonTextReader(strdr))
            {
                var deserialized = ser.Deserialize(jtr, type);
                return deserialized;
            }
        });
    }

    protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext)
    {
         JsonSerializer ser = JsonSerializer.Create(settings);

         return Task.Factory.StartNew(() =>
         {
              using (JsonTextWriter w = new JsonTextWriter(new StreamWriter(stream, Encoding)) { CloseOutput = false})
              {
                   ser.Serialize(w, value);
                   w.Flush();
              }
         });
    }
}    
Run Code Online (Sandbox Code Playgroud)