将JSON格式的DateTime传递给ASP.NET MVC

13

我们知道MVC以/Date(1240718400000)/这种格式返回JsonResult的日期时间,并且我们知道如何在JS中解析它。

然而,似乎MVC不接受以这种方式发送DateTime参数。例如,我有以下操作:

[HttpGet]
public ViewResult Detail(BookDetail details) { //... }

BookDetail类包含一个名为CreateDate的DateTime字段,我使用以下格式从JS传递了一个JSON对象:

{"CreateDate": "/Date(1319144453250)/"}

CreateDate被认为是空的。

如果我以这种方式传递JSON,它可以正常工作:

{"CreateDate": "2011-10-10"}

问题是我不能轻松地更改客户端代码,必须坚持使用/Date(1319144453250)/这种格式。我必须在服务器端进行更改。

如何解决这个问题?与ModelBinder有关吗?

非常感谢您的帮助!


另一个更简单的解决方案在这里 - Mohsen Afshin
3个回答

7

正如你所怀疑的那样,问题出在模型绑定上。

为了解决这个问题,创建一个自定义类型,我们称之为JsonDateTime。因为DateTime是一个结构体,所以无法从它继承,因此创建以下类:

public class JsonDateTime
{
    public JsonDateTime(DateTime dateTime)
    {
        _dateTime = dateTime;
    }

    private DateTime _dateTime;

    public DateTime Value
    {
        get { return _dateTime; }
        set { _dateTime = value; }
    }
}

将CreateDate更改为此类型。 接下来,我们需要一个自定义模型绑定程序,如下所示:

public class JsonDateTimeModelBinder : IModelBinder  
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString(); 
        return new DateTime(Int64.Parse(
            value.Substring(6).Replace(")/",String.Empty))); // "borrowed" from skolima's answer
    }
}

然后,在Global.asax.cs中的Application_Start方法中,注册您的自定义ModelBinder:

ModelBinders.Binders.Add(typeof(JsonDateTime), new JsonDateTimeModelBinder());

谢谢counsellorben(假设这是您的名字:),我会试一下。您能告诉我更多关于ModelBinder的信息,并可能指出MVC源代码中相关的区域吗? - tshao
你应该看一下DefaultModelBinder。在MVC文件夹中的System.Web.Mvc项目中查看DefaultModelBinder.cs - counsellorben
2
为什么要创建包装器对象JsonDateTime?您提到“...因为DateTime是一个结构体,所以您无法从中继承”,但我在这里看不到任何继承被使用。 - Marchy
在MVC 4中,我需要使用... bindingContext.ValueProvider.GetValue (bindingContext.ModelName) .RawValue.ToString() ... - Dai Bok

2

我认为使用自定义模型绑定器可以解决问题。下面的模型绑定器类将适用于两种情况。它将解析所有 .NET 可识别的日期字符串以及 JSON 格式的日期字符串。无需更改任何现有代码。

public class DateTimeModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = base.BindModel(controllerContext, bindingContext);
        if (model == null && (bindingContext.ModelType == typeof(DateTime) || bindingContext.ModelType == typeof(DateTime?)))
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (value == null || String.IsNullOrEmpty(value.AttemptedValue))
                model = (bindingContext.ModelType == typeof(DateTime?)) ? null : (object)DateTime.MinValue;
            else if (Regex.IsMatch(value.AttemptedValue, @"\/Date\(\d+\)\/"))
                model = new DateTime(1970, 1, 1).AddMilliseconds(Int64.Parse(value.AttemptedValue.Substring(6).Replace(")/", String.Empty))).ToLocalTime();
            //else //Any other format
        }
        return model;
    }
}

在Global.asax的Application_Start中配置模型绑定器。
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        //Your Existing Code....

        ModelBinders.Binders.Add(typeof(DateTime), new DateTimeModelBinder());
        ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeModelBinder());
    }
}

如果有帮助,请投票


2

在您的模型中,使用以下代码解析日期:

// property
String CreateDate;
DateTime CreateDateAsDate;

// drop prefix, drop suffix, parse as long and read as ticks
CreateDateAsDate date = new DateTime(Int64.Parse(
    CreateDate.Substring(6).Replace(")/",String.Empty)));

CreateDate 被识别为 null,所以这不起作用。(除非我将 CreateDate 定义为 String,但我真的不想这样做...) - tshao
你将拥有两个属性,CreateDate作为字符串和CreateDateAsDate作为实际解析值。否则恐怕无法正常工作。 - skolima
似乎这是唯一的方法...我会再等一会儿看看是否有更多的回复;-) - tshao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接