簡體   English   中英

MVC DateTime綁定具有不正確的日期格式

[英]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

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

  1. RouteData(上圖未顯示)
  2. URI查詢字符串
  3. 申請表

然而,只有最后一個才會有文化意識。 從本地化的角度來看,有一個很好的理由。 想象一下,我寫了一個網絡應用程序,顯示我在線發布的航班信息。 我通過點擊當天的鏈接(可能是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/

加里克 - https://stackoverflow.com/a/2468447/578208

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

它在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;
}

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

    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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM