[英]MVC DateTime binding with incorrect date format
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的默認模型綁定器中使用的日期格式? 默認型號綁定器不應該使用您的本地化設置嗎?
我剛剛用一些更詳盡的谷歌搜索找到了答案:
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,因此在從表單返回時需要尊重它。
我會全球設定你的文化。 ModelBinder選擇了!
<system.web>
<globalization uiCulture="en-AU" culture="en-AU" />
或者您只需更改此頁面。
但是在web.config中我認為更好
我一直遇到與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/
它在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值:
/公司/新聞/可2001%%202008
/公司/新聞/ 2008-05-01
/公司/新聞/ 2008年5月1日
我強烈建議使用yyyy-mm-dd因為它更便攜。 你真的不想處理多種本地化格式。 如果有人在5月1日而不是1月5日預訂航班,那么您將遇到大問題!
注意:如果yyyy-mm-dd在所有文化中得到普遍解析,我也不清楚,所以也許有人知道可以添加評論。
我在我的MVC4上設置了以下配置,它就像一個魅力
<globalization uiCulture="auto" culture="auto" />
嘗試使用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());
}
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");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.