当前位置:  开发笔记 > 编程语言 > 正文

MVC DateTime绑定具有不正确的日期格式

如何解决《MVCDateTime绑定具有不正确的日期格式》经验,为你挑选了7个好方法。

Asp.net-MVC现在允许隐式绑定DateTime对象.我有一个行动

public ActionResult DoSomething(DateTime startDate) 
{ 
... 
}

这成功地将字符串从ajax调用转换为DateTime.但是,我们使用日期格式dd/MM/yyyy; MVC正在转换为MM/dd/yyyy.例如,使用字符串'09/02/2009'提交对操作的调用会导致DateTime为'02/09/2009 00:00:00',或在我们的本地设置中为9月2日.

我不想为了日期格式而滚动我自己的模型绑定器.但是,如果MVC能够为我执行此操作,则无需更改操作以接受字符串然后使用DateTime.Parse.

有没有办法改变DateTime的默认模型绑定器中使用的日期格式?默认型号绑定器不应该使用您的本地化设置吗?



1> Sam Wessel..:

我刚刚用一些更详尽的谷歌搜索找到了答案:

Melvyn Harbour详细解释了为什么MVC使用日期的方式,以及如何在必要时覆盖它:

http://weblogs.asp.net/melvynharbour/archive/2008/11/21/mvc-modelbinder-and-localization.aspx

在查找要解析的值时,框架以特定顺序查找:

    RouteData(上图未显示)

    URI查询字符串

    申请表

然而,只有最后一个才会有文化意识.从本地化的角度来看,有一个很好的理由.想象一下,我写了一个网络应用程序,显示我在线发布的航班信息.我通过点击当天的链接(可能是http://www.melsflighttimes.com/Flights/2008-11-21)查找特定日期的航班,然后想通过电子邮件将该链接发送给我的同事美国.我们可以保证我们将同时查看同一页数据的唯一方法是使用InvariantCulture.相比之下,如果我使用表格预订我的航班,一切都在紧张的周期中发生.当数据写入表单时,数据可以尊重CurrentCulture,因此在从表单返回时需要尊重它.


我强烈反对技术上这是正确的.模型绑定器应始终与POST和GET相同.如果不变的文化是GET的方式,也可以用于POST.根据http动词改变行为是没有意义的.

2> Peter Gfader..:

我会全球设定你的文化.ModelBinder选择了!

  
    

或者您只需更改此页面.
但是在web.config中我认为更好


不适合我.如果我通过23/10/2010,日期仍然为null.

3> WernerVA..:

我一直遇到与DateTime模型属性绑定的短日期格式相同的问题.在查看了许多不同的例子(不仅仅是关于DateTime)之后,我将以下内容放在一起:

using System;
using System.Globalization;
using System.Web.Mvc;

namespace YourNamespaceHere
{
    public class CustomDateBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext == null)
                throw new ArgumentNullException("controllerContext", "controllerContext is null.");
            if (bindingContext == null)
                throw new ArgumentNullException("bindingContext", "bindingContext is null.");

            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            if (value == null)
                throw new ArgumentNullException(bindingContext.ModelName);

            CultureInfo cultureInf = (CultureInfo)CultureInfo.CurrentCulture.Clone();
            cultureInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);

            try
            {
                var date = value.ConvertTo(typeof(DateTime), cultureInf);

                return date;
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                return null;
            }
        }
    }

    public class NullableCustomDateBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext == null)
                throw new ArgumentNullException("controllerContext", "controllerContext is null.");
            if (bindingContext == null)
                throw new ArgumentNullException("bindingContext", "bindingContext is null.");

            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            if (value == null) return null;

            CultureInfo cultureInf = (CultureInfo)CultureInfo.CurrentCulture.Clone();
            cultureInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);

            try
            {
                var date = value.ConvertTo(typeof(DateTime), cultureInf);

                return date;
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                return null;
            }
        }
    }
}

为了与在Global ASAX文件中注册路由等的方式保持一致,我还在我的MVC4项目的App_Start文件夹中添加了一个新的sytatic类,名为CustomModelBinderConfig:

using System;
using System.Web.Mvc;

namespace YourNamespaceHere
{
    public static class CustomModelBindersConfig
    {
        public static void RegisterCustomModelBinders()
        {
            ModelBinders.Binders.Add(typeof(DateTime), new CustomModelBinders.CustomDateBinder());
            ModelBinders.Binders.Add(typeof(DateTime?), new CustomModelBinders.NullableCustomDateBinder());
        }
    }
}

然后我从我的Global ASASX Application_Start中调用静态RegisterCustomModelBinders,如下所示:

protected void Application_Start()
{
    /* bla blah bla the usual stuff and then */

    CustomModelBindersConfig.RegisterCustomModelBinders();
}

这里一个重要的注意事项是,如果您将DateTime值写入这样的隐藏字段:

@Html.HiddenFor(model => model.SomeDate) // a DateTime property
@Html.Hiddenfor(model => model) // a model that is of type DateTime

我这样做了,页面上的实际值是"MM/dd/yyyy hh:mm:ss tt"而不是"dd/MM/yyyy hh:mm:ss tt",就像我想要的那样.这导致我的模型验证失败或返回错误的日期(显然交换日期和月份值).

经过大量的努力和尝试失败后,解决方案是在Global.ASAX中为每个请求设置文化信息:

protected void Application_BeginRequest()
{
    CultureInfo cInf = new CultureInfo("en-ZA", false);  
    // NOTE: change the culture name en-ZA to whatever culture suits your needs

    cInf.DateTimeFormat.DateSeparator = "/";
    cInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
    cInf.DateTimeFormat.LongDatePattern = "dd/MM/yyyy hh:mm:ss tt";

    System.Threading.Thread.CurrentThread.CurrentCulture = cInf;
    System.Threading.Thread.CurrentThread.CurrentUICulture = cInf;
}

如果你将它粘贴在Application_Start甚至Session_Start中它将无法工作,因为它将它分配给会话的当前线程.众所周知,Web应用程序是无状态的,因此先前为您的请求提供服务的线程与服务当前请求的线程相同,因此您的文化信息已转移到数字天空中的GC.

谢谢你:Ivan Zlatev - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/

加里克 - /sf/ask/17360801/

德米特里 - /sf/ask/17360801/



4> 小智..:

它在MVC 3中会略有不同.

假设我们有一个控制器和一个带Get方法的视图

public ActionResult DoSomething(DateTime dateTime)
{
    return View();
}

我们应该添加ModelBinder

public class DateTimeBinder : IModelBinder
{
    #region IModelBinder Members
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        DateTime dateTime;
        if (DateTime.TryParse(controllerContext.HttpContext.Request.QueryString["dateTime"], CultureInfo.GetCultureInfo("en-GB"), DateTimeStyles.None, out dateTime))
            return dateTime;
        //else
        return new DateTime();//or another appropriate default ;
    }
    #endregion
}

和Global.asax的Application_Start()中的命令

ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());


另外,我发现`DateTime?'只有在你用`typeof(DateTime?)`添加对`ModelBinders.Binders.Add`的另一个调用时才有效.

5> Simon_Weaver..:

值得注意的是,即使没有创建自己的模型绑定器,也可以解析多种不同的格式.

例如,在美国,以下所有字符串都是等效的,并自动绑定到相同的 DateTime值:

/公司/新闻/可2001%%202008

/公司/新闻/ 2008-05-01

/公司/新闻/ 2008年5月1日

我强烈建议使用yyyy-mm-dd因为它更便携.你真的不想处理多种本地化格式.如果有人在5月1日而不是1月5日预订航班,那么您将遇到大问题!

注意:如果yyyy-mm-dd在所有文化中得到普遍解析,我也不清楚,所以也许有人知道可以添加评论.


既然没有人说yyyy-MM-dd不通用,我想是的.

6> JeeShen Lee..:

我在我的MVC4上设置了以下配置,它就像一个魅力



这对我也有用.请注意,globalization元素位于Configuration> System.Web下.http://msdn.microsoft.com/en-us/library/hy4kkhe0%28v=vs.85%29.aspx

7> rnofenko..:

尝试使用toISOString().它以ISO8601格式返回字符串.

GET方法

JavaScript的

$.get('/example/doGet?date=' + new Date().toISOString(), function (result) {
    console.log(result);
});

C#

[HttpGet]
public JsonResult DoGet(DateTime date)
{
    return Json(date.ToString(), JsonRequestBehavior.AllowGet);
}

POST方法

JavaScript的

$.post('/example/do', { date: date.toISOString() }, function (result) {
    console.log(result);
});

C#

[HttpPost]
public JsonResult Do(DateTime date)
{
     return Json(date.ToString());
}

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有