2009-02-09 90 views
119

Asp.net-MVC現在允許隱式綁定DateTime對象。我有一個行動帶錯誤日期格式的MVC DateTime綁定

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

這成功地將字符串從ajax調用轉換爲DateTime。但是,我們使用日期格式dd/MM/yyyy; MVC正在轉換爲MM/dd/yyyy。 例如,使用字符串'09/02/2009'提交對操作的調用會導致日期時間爲'02/09/2009 00:00:00',或在本地設置中爲9月2日。

爲了日期格式的緣故,我不想滾動我自己的模型聯編程序。但似乎不必更改動作來接受一個字符串,然後使用DateTime.Parse如果MVC能夠爲我做這個。

有什麼辦法可以改變DateTime默認模型聯編程序中使用的日期格式嗎?不應該默認模型聯編程序使用您的本地化設置嗎?

+0

嘿..只要改變您的系統日期格式 - DD/MM/YYYY以MM/DD/YYYY和做到了。我也有同樣的問題,我通過更改系統日期格式來解決它。 – banny 2015-04-27 06:20:54

+0

@banny如果應用程序是全球性的,可能每個人都有不同的日期時間格式,你怎麼能這樣做? ,你不應該去改變每一個日期時間格式.. – 2016-02-02 11:43:50

+0

這些答案都沒有幫助我。表單需要進行本地化。一些用戶可能有一種方式的日期,其他方式可能有其他用戶。在web.config中設置一些東西。或global.asax不會幫助。我會繼續尋找更好的答案,但有一種方法只是將日期作爲字符串處理,直到我回到c#。 – astrosteve 2016-03-25 15:11:30

回答

151

我剛剛找到了答案,這與一些更詳盡的谷歌搜索:

梅爾文港擁有爲什麼MVC工作的日期方式是這樣一個詳盡的解釋,以及如何在必要時覆蓋此:

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

當尋找解析值,框架會查找特定的順序分別是:

  1. 的RouteData(上面沒有顯示)
  2. URI查詢字符串
  3. 申請表

只有最後這些都將是文化的瞭解不過。從本地化的角度來看,這有很好的理由。想象一下,我寫了一個web應用程序,顯示我在線發佈的航班信息。我通過點擊當天的鏈接查找航班(可能類似於http://www.melsflighttimes.com/Flights/2008-11-21),然後希望通過電子郵件將鏈接發送給我在美國的同事。如果使用InvariantCulture,我們可以保證我們都會查看同一頁數據的唯一方法。相比之下,如果我使用表單來預訂我的航班,那麼所有事情都會在緊張的週期中發生。數據在寫入表單時可以尊重CurrentCulture,因此在從表單返回時需要尊重它。

+0

會做。發佈問題後48小時內該功能被禁用。 – 2009-02-10 09:57:03

+37

我在技術上強烈表示不同意這是正確的。模型聯編程序應始終與POST和GET行爲相同。如果不變的文化是GET的方式去做POST也是。根據http動詞改變行爲是無意義的。 – 2013-04-02 14:31:21

+1

+1投票澄清問題。 – 2013-04-02 14:53:28

8

還值得注意的是,即使沒有創建自己的模型綁定器,多種不同的格式也可能是可解析的。

例如,在美國所有的下列字符串是等效的,並自動獲取綁定到相同 DateTime值:

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

/公司/按/ 2008-05-01

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

我最好強建議使用yyyy-mm-dd,因爲它更便於攜帶。你真的不想處理處理多個本地化的格式。如果有人在5月1日而不是1月5日預訂航班,那麼你將遇到大問題!

注意:如果yyyy-mm-dd在所有文化中都得到了全面解析,那麼我不太清楚,所以也許有人知道可以添加評論。

34

我會全球性地設置您的文化。 ModelBinder把它挑起來!

<system.web> 
    <globalization uiCulture="en-AU" culture="en-AU" /> 

或者你只是改變這個頁面。
但全球在web.config中,我認爲是更好的

13

它要在MVC略有不同3.

假設我們有一個控制器和與獲取方法的視圖

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

我們應該添加的Global.asax

012的模型綁定器

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 
} 

和在的Application_Start(命令)

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

我把我的MVC4下面的配置,它就像一個魅力

<globalization uiCulture="auto" culture="auto" /> 
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); 
        } 
       } 

      } 
     } 
    } 
} 
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; 
} 
27

我一直有與短日期格式結合的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文件中regiseterd我還增加了一個新的sytatic類的App_Start方式:看很多不同的例子(不僅涉及日期時間),我放在一起follwing後我MVC4項目的文件夾命名爲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()); 
     } 
    } 
} 

我然後只調用靜態RegisterCustomModelBinders從我的全球ASASX的Application_Start是這樣的:

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

    CustomModelBindersConfig.RegisterCustomModelBinders(); 
} 

這裏一個重要的註釋是,如果你一個DateTime值寫入這樣的hiddenfield:

@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。

感謝去: 伊萬·勒蒂文 - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/

garik - https://stackoverflow.com/a/2468447/578208

德米特里 - https://stackoverflow.com/a/11903896/578208

3

嘗試使用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()); 
} 
0

我設置CurrentCultureCurrentUICulture我自定義的基本控制器

protected override void Initialize(RequestContext requestContext) 
    { 
     base.Initialize(requestContext); 

     Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB"); 
     Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB"); 
    }