Liaison MVC DateTime avec format de date incorrect

Asp.net-MVC permet désormais la liaison implicite d’objects DateTime. J’ai une action dans le sens de

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

Cela convertit avec succès une chaîne d’un appel ajax en un DateTime. Cependant, nous utilisons le format de date jj / MM / aaaa; MVC se convertit au MM / jj / aaaa. Par exemple, l’envoi d’un appel à l’action avec une chaîne ’09 / 02/2009 ‘donne lieu à un DateTime 02/09/2009 00:00:00’ ou le 2 septembre dans nos parameters locaux.

Je ne veux pas rouler mon propre modèle pour un format de date. Mais il semble inutile de modifier l’action pour accepter une chaîne et utiliser DateTime.Parse si MVC est capable de le faire pour moi.

Existe-t-il un moyen de modifier le format de date utilisé dans le classeur par défaut pour DateTime? Le classeur par défaut ne devrait-il pas utiliser vos parameters de localisation?

    Je viens de trouver la réponse à cela avec un googling plus exhaustif:

    Melvyn Harbour a une explication approfondie de la raison pour laquelle MVC fonctionne avec les dates comme il le fait et comment vous pouvez y remédier si nécessaire:

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

    Lorsque vous recherchez la valeur à parsingr, le framework recherche dans un ordre spécifique à savoir:

    1. RouteData (non illustré ci-dessus)
    2. Chaîne de requête URI
    3. Formulaire de demande

    Seuls les derniers seront conscients de la culture. Il y a une très bonne raison à cela, du sharepoint vue de la localisation. Imaginez que j’ai écrit une application Web montrant les informations de vol que je publie en ligne. Je recherche des vols à une certaine date en cliquant sur un lien pour ce jour (peut-être quelque chose comme http://www.melsflighttimes.com/Flights/2008-11-21 ), puis je souhaite envoyer ce lien à mon collègue par e-mail. les Etats Unis. La seule façon de garantir que nous regarderons tous les deux la même page de données est d’utiliser InvariantCulture. En revanche, si j’utilise un formulaire pour réserver mon vol, tout se passe dans un cycle serré. Les données peuvent respecter la CurrentCulture lorsqu’elle est écrite dans le formulaire et doivent donc la respecter lorsqu’elle revient du formulaire.

    Je définirais globalement vos cultures. ModelBinder ramasse ça!

        

    Ou vous changez simplement ceci pour cette page.
    Mais globalement, dans web.config, je pense que c’est mieux

    J’ai eu le même problème avec la liaison de format de date courte aux propriétés du modèle DateTime. Après avoir examiné de nombreux exemples différents (pas seulement concernant DateTime), j’ai rassemblé les éléments suivants:

     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 restr fidèle à la façon dont les routes, etc., sont enregistrées dans le fichier ASAX global, j’ai également ajouté une nouvelle classe statique dans le dossier App_Start de mon projet MVC4, 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’appelle alors simplement les static RegisterCustomModelBinders de mon Global ASASX Application_Start comme ceci:

     protected void Application_Start() { /* bla blah bla the usual stuff and then */ CustomModelBindersConfig.RegisterCustomModelBinders(); } 

    Une note importante est que si vous écrivez une valeur DateTime dans un champ caché 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 de la page était au format “MM / jj / aaaa hh: mm: ss tt” au lieu de “jj / MM / aaaa hh: mm: ss tt” comme je le voulais. Cela a provoqué l’échec de la validation de mon modèle ou le retour de la date incorrecte (en intervertissant évidemment les valeurs du jour et du mois).

    Après de nombreuses tentatives et tentatives infructueuses, la solution consistait à définir les informations de culture pour chaque requête en faisant cela dans 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; } 

    Cela ne fonctionnera pas si vous le collez dans Application_Start ou même Session_Start car cela l’assigne au thread en cours pour la session. Comme vous le savez, les applications Web sont sans état, de sorte que le thread qui traitait votre requête précédemment est le même que celui qui gère votre requête actuelle. Par conséquent, vos informations de culture sont allées au grand GC dans le ciel numérique.

    Merci à: 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

    Cela va être légèrement différent dans MVC 3.

    Supposons que nous ayons un contrôleur et une vue avec la méthode Get

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

    Nous devrions append ModelBinder

     public class DateTimeBinder : IModelBinder { #region IModelBinder Members public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { DateTime dateTime; if (DateTime.TryParse(controllerContext.HttpContext.Request.QuerySsortingng["dateTime"], CultureInfo.GetCultureInfo("en-GB"), DateTimeStyles.None, out dateTime)) return dateTime; //else return new DateTime();//or another appropriate default ; } #endregion } 

    et la commande dans Application_Start () de Global.asax

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

    Il est également intéressant de noter que même sans créer votre propre modèle, plusieurs formats différents peuvent être analysés.

    Par exemple, aux États-Unis, toutes les chaînes suivantes sont équivalentes et automatiquement liées à la même valeur DateTime:

    / company / press / peut% 2001% 202008

    / compagnie / presse / 2008-05-01

    / company / press / 05-01-2008

    Je suggère fortement d’utiliser yyyy-mm-dd parce que c’est beaucoup plus portable. Vous ne voulez vraiment pas manipuler plusieurs formats localisés. Si quelqu’un réserve un vol le 1er mai au lieu du 5 janvier, vous aurez de gros problèmes!

    NB: Je ne suis pas très clair si yyyy-mm-dd est universellement analysé dans toutes les cultures alors peut-être que quelqu’un qui sait peut append un commentaire.

    Je mets la configuration ci-dessous sur mon MVC4 et cela fonctionne comme un charme

      

    Essayez d’utiliser toISOSsortingng (). Il renvoie une chaîne au format ISO8601.

    Méthode GET

    javascript

     $.get('/example/doGet?date=' + new Date().toISOSsortingng(), function (result) { console.log(result); }); 

    c #

     [HttpGet] public JsonResult DoGet(DateTime date) { return Json(date.ToSsortingng(), JsonRequestBehavior.AllowGet); } 

    Méthode POST

    javascript

     $.post('/example/do', { date: date.toISOSsortingng() }, function (result) { console.log(result); }); 

    c #

     [HttpPost] public JsonResult Do(DateTime date) { return Json(date.ToSsortingng()); } 
      public class DateTimeFilter : ActionFilterAtsortingbute { 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.QuerySsortingng[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.QuerySsortingng[bindingContext.ModelName]; if (ssortingng.IsNullOrEmpty(str)) return null; var date = DateTime.ParseExact(str, "dd.MM.yyyy", null); return date; } 

    Je mets en place CurrentCulture et CurrentUICulture mon contrôleur de base personnalisé

      protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB"); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB"); }