【问题标题】:Pass a JSON format DateTime to ASP.NET MVC将 JSON 格式的 DateTime 传递给 ASP.NET MVC
【发布时间】:2011-10-21 10:21:36
【问题描述】:

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

但是,MVC 似乎不接受以这种方式发送的 DateTime 参数。例如,我有以下 Action。

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

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

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

CreateDate 被识别为空。

如果我以这种方式传递 JSON,它会按预期工作:

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

问题是我不能以简单的方式更改客户端代码,必须坚持 /Date(1319144453250)/ 这种格式。我必须在服务器端进行更改。

如何解决这个问题?这和 ModelBinder 有什么关系吗?

提前非常感谢!

【问题讨论】:

标签: asp.net-mvc json


【解决方案1】:

正如您所怀疑的,问题是模型绑定问题。

要解决这个问题,请创建一个自定义类型,并将其命名为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());

【讨论】:

  • 谢谢辅导员本(假设这是你的名字:),我会试试看。你能告诉我更多关于 ModelBinder 的信息,或者指出 MVC 源代码中的相关区域吗?
  • 你应该看看 DefaultModelBinder。在 MVC 文件夹中的 System.Web.Mvc 项目中查看 DefaultModelBinder.cs
  • 为什么要创建包装对象 JsonDateTime?你提到'......因为 DateTime 是一个结构,你不能从它继承',但我看到这里没有使用继承。
  • 在 MVC 4 中我需要使用 ...bindingContext.ValueProvider.GetValue(bindingContext.ModelName).RawValue.ToString() ...
【解决方案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 被识别为空,所以这不起作用。 (除非我将 CreateDate 定义为 String,但我真的不想那样做……)
  • 您将拥有两个属性, CreateDate as String 和 CreateDateAsDate 与实际解析值。否则恐怕行不通。
  • 似乎这是唯一的方法...我会等待更多的回复;-)
【解决方案3】:

我认为使用自定义模型绑定器可以解决问题。下面的模型绑定器类将适用于这两种情况。它将解析所有 dot 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());
    }
}

如果有帮助请投票

【讨论】:

    猜你喜欢
    • 2017-05-24
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多