J'ai eu le même problème avec le format de date courte liaison de type DateTime propriétés du modèle. Après avoir regardé de nombreux exemples (il ne concerne pas seulement DateTime) j'ai mis en place les suivantes:
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;
}
}
}
}
Pour garder le chemin qui les routes etc sont regiseterd dans le Global ASAX fichier j'ai également ajouté une nouvelle sytatic classe à la App_Start dossier de mon MVC4 projet nommé 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());
}
}
}
J'ai ensuite il suffit d'appeler la statique RegisterCustomModelBinders de mes ASASX Application_Start comme ceci:
protected void Application_Start()
{
/* bla blah bla the usual stuff and then */
CustomModelBindersConfig.RegisterCustomModelBinders();
}
Il est important de noter ici est que si vous écrivez une valeur de type DateTime à un hiddenfield comme ceci:
@Html.HiddenFor(model => model.SomeDate) // a DateTime property
@Html.Hiddenfor(model => model) // a model that is of type DateTime
Je l'ai fait et la valeur réelle sur la page dans le format "MM/jj/aaaa hh:mm:ss tt" au lieu de "dd/MM/yyyy hh:mm:ss tt" comme je le voulais. Ce la cause de mon modèle de validation d'échouer ou de retour de la mauvaise date (évidemment l'échange le jour et le mois de valeurs autour).
Après beaucoup de casse-tête et de tentatives infructueuses, la solution a été de définir la culture d'info pour chaque demande de faire cela dans le monde.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;
}
Il ne fonctionnera pas si vous vous en tenez dans Application_Start ou même Session_Start depuis qu'il l'attribue à un thread en cours de la session. Comme vous le savez bien, les applications web sont apatrides, de sorte que le thread qui a réparé votre demande précédemment n'est donc pas le même thread serviceing votre demande ainsi que votre culture info est allé à la grande GC dans le ciel numérique.
Les remerciements vont à:
Ivan Zlatev - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/
garik - http://stackoverflow.com/a/2468447/578208
Dmitry - http://stackoverflow.com/a/11903896/578208