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默认模型绑定器中使用的日期格式?默认的模型绑定器不应该使用您的本地化设置吗?
答案 0 :(得分:161)
我刚刚用一些更详尽的谷歌搜索找到了答案:
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,因此从表单返回时需要尊重它。
答案 1 :(得分:35)
我会在全球范围内设定你的文化。 ModelBinder选择了!
<system.web>
<globalization uiCulture="en-AU" culture="en-AU" />
或者您只需更改此页面。
但是在web.config中全局我觉得更好
答案 2 :(得分:29)
我遇到了与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;
}
}
}
}
为了保持在全局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/
答案 3 :(得分:13)
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());
答案 4 :(得分:8)
值得注意的是,即使没有创建自己的模型绑定器,也可以解析多种不同的格式。
例如在美国,以下所有字符串都是等效的,并自动绑定到相同的 DateTime值:
/公司/媒体/可%2001%202008
/公司/媒体/ 2008-05-01
/公司/媒体/ 2008年5月1日
我强烈建议使用yyyy-mm-dd因为它更便携。你真的不想处理多种本地化格式。如果有人在5月1日而不是1月5日预订航班,那么您将遇到大问题!
注意:如果yyyy-mm-dd在所有文化中得到普遍解析,我也不清楚,所以也许知道的人可以添加评论。
答案 5 :(得分:5)
我在MVC4上设置了以下配置,它就像魅力一样
<globalization uiCulture="auto" culture="auto" />
答案 6 :(得分:5)
尝试使用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());
}
答案 7 :(得分:1)
public class DateTimeFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.RequestType == "GET")
{
foreach (var parameter in filterContext.ActionParameters)
{
var properties = parameter.Value.GetType().GetProperties();
foreach (var property in properties)
{
Type type = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
if (property.PropertyType == typeof(System.DateTime) || property.PropertyType == typeof(DateTime?))
{
DateTime dateTime;
if (DateTime.TryParse(filterContext.HttpContext.Request.QueryString[property.Name], CultureInfo.CurrentUICulture, DateTimeStyles.None, out dateTime))
property.SetValue(parameter.Value, dateTime,null);
}
}
}
}
}
}
答案 8 :(得分:1)
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var str = controllerContext.HttpContext.Request.QueryString[bindingContext.ModelName];
if (string.IsNullOrEmpty(str)) return null;
var date = DateTime.ParseExact(str, "dd.MM.yyyy", null);
return date;
}
答案 9 :(得分:0)
我设置CurrentCulture
和CurrentUICulture
我的自定义基本控制器
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
}