MVCdate时间绑定与不正确的date格式
Asp.net-MVC现在允许隐式绑定DateTime对象。 我有一个行动
public ActionResult DoSomething(DateTime startDate) { ... }
这成功地将string从ajax调用转换为DateTime。 但是,我们使用date格式dd / MM / yyyy; MVC转换为MM / dd / yyyy。 例如,使用string'09 / 02/2009'提交对操作的调用会导致date时间为'02 / 09/2009 00:00:00',或在本地设置中为9月2日。
为了date格式,我不想推出自己的模型绑定器。 但似乎不必要改变的行动接受一个string,然后使用DateTime.Parse如果MVC是能够做到这一点对我来说。
有什么办法可以改变默认模型联编程序中用于DateTime的date格式吗? 不应该默认模型联编程序使用您的本地化设置吗?
我刚刚find了一些更详尽的谷歌search的答案:
Melvyn Harbour对MVC为什么会按照它的方式进行工作进行了详尽的解释,以及如果有必要,您可以如何覆盖它:
http://weblogs.asp.net/melvynharbour/archive/2008/11/21/mvc-modelbinder-and-localization.aspx
在查找要parsing的值时,框架按以下顺序查找:
- RouteData(上面没有显示)
- URI查询string
- 申请表
然而,只有最后一个才会有文化意识。 从本地化的angular度来看,这有很好的理由。 想象一下,我写了一个web应用程序,显示我在线发布的航class信息。 我点击当天的链接查找某个date的航class(可能类似http://www.melsflighttimes.com/Flights/2008-11-21 ),然后通过电子邮件将链接发送给我的同事美国。 如果使用InvariantCulture,那么我们可以保证我们都将查看同一页数据的唯一方法。 相比之下,如果我使用表单来预订我的航class,那么一切都在紧张的周期中进行。 数据在写入表单时可以尊重CurrentCulture,从表单返回时需要尊重它。
我会全球性地设置您的文化。 ModelBinder挑起来!
<system.web> <globalization uiCulture="en-AU" culture="en-AU" />
或者你只是改变这个页面。
但全球在web.config我认为是更好的
我一直有与短date格式绑定到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文件中注册,我还在名为CustomModelBinderConfig的MVC4项目的App_Start文件夹中添加了一个新的sytatic类:
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”,就像我想要的那样。 这导致我的模型validation失败或返回错误的date(显然交换周围的date和月份值)。
经过大量的头部划伤和失败的尝试,解决scheme是通过在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/
这在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());
还值得注意的是,即使没有创build自己的模型绑定器,多种不同的格式也可以被parsing。
例如,在美国,以下所有string都是相同的,并自动绑定到相同的 DateTime值:
/公司/新闻/可2001%%202008
/公司/新闻/ 2008-05-01
/公司/新闻/ 2008年5月1日
我强烈build议使用yyyy-mm-dd,因为它更便于携带。 你真的不想处理处理多个本地化的格式。 如果有人在5月1日而不是1月5日预订航class,那么你将遇到大问题!
注意:如果yyyy-mm-dd在所有文化中被普遍parsing,我不是很清楚,所以也许有人知道可以添加评论。
我在我的MVC4上设置了下面的configuration,它就像一个魅力
<globalization uiCulture="auto" culture="auto" />
尝试使用toISOString()。 它以ISO8601格式返回string。
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()); }
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); } } } } } }
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; }
我设置了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"); }