Ich habe das gleiche Problem mit der Bindung des kurzen Datumsformats an die DateTime-Modelleigenschaften. Nachdem ich mir viele verschiedene Beispiele angesehen habe (nicht nur in Bezug auf DateTime), habe ich Folgendes zusammengestellt:
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;
}
}
}
}
Um sicherzustellen, dass Routen usw. in der globalen ASAX-Datei registriert werden, habe ich dem Ordner App_Start meines MVC4-Projekts mit dem Namen CustomModelBinderConfig eine neue sytatische Klasse hinzugefügt:
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());
}
}
}
Ich rufe dann einfach die statischen RegisterCustomModelBinders von meinem globalen ASASX Application_Start wie folgt auf:
protected void Application_Start()
{
/* bla blah bla the usual stuff and then */
CustomModelBindersConfig.RegisterCustomModelBinders();
}
Ein wichtiger Hinweis hierbei ist, dass, wenn Sie einen DateTime-Wert in ein verstecktes Feld wie folgt schreiben:
@Html.HiddenFor(model => model.SomeDate) // a DateTime property
@Html.Hiddenfor(model => model) // a model that is of type DateTime
Ich habe das getan und der tatsächliche Wert auf der Seite hatte das Format "MM / TT / JJJJ hh: mm: ss tt" anstelle von "TT / MM / JJJJ hh: mm: ss tt", wie ich wollte. Dies führte dazu, dass meine Modellvalidierung entweder fehlschlug oder das falsche Datum zurückgab (offensichtlich wurden die Werte für Tag und Monat vertauscht).
Nach vielen Kopfkratzern und fehlgeschlagenen Versuchen bestand die Lösung darin, die Kulturinformationen für jede Anfrage festzulegen, indem Sie dies in Global.ASAX tun:
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;
}
Es funktioniert nicht, wenn Sie es in Application_Start oder sogar Session_Start stecken, da es dem aktuellen Thread für die Sitzung zugewiesen wird. Wie Sie wissen, sind Webanwendungen zustandslos, sodass der Thread, der Ihre Anfrage zuvor bearbeitet hat, nicht derselbe Thread ist, der Ihre aktuelle Anfrage bearbeitet. Daher wurden Ihre Kulturinformationen an den großen GC im digitalen Himmel gesendet.
Vielen Dank an: Ivan Zlatev - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/
garik - https://stackoverflow.com/a/2468447/578208
Dmitry - https://stackoverflow.com/a/11903896/578208