Question

Je voudrais écrire mon propre modèle de liaison pour le type de DateTime. Tout d'abord je voudrais écrire un nouvel attribut que je peux joindre à ma propriété de modèle comme:

[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}

Ceci est la partie facile. Mais la partie de liant est un peu plus difficile. Je voudrais ajouter un nouveau modèle de liaison pour le type DateTime. Je peux soit

  • mettre en œuvre l'interface IModelBinder et écrire ma propre méthode BindModel()
  • hériter de DefaultModelBinder et remplacer la méthode de BindModel()

Mon modèle a une propriété comme on le voit ci-dessus (Birth). Ainsi, lorsque le modèle tente de lier les données de demande à cette propriété, s'invoqué le BindModel(controllerContext, bindingContext) de mon classeur modèle. Tout va bien, mais. Comment puis-je obtenir les attributs propriété du contrôleur / BindingContext, pour analyser correctement ma date ? Comment puis-je accéder à la PropertyDesciptor de Birth de propriété?

Modifier

En raison de la séparation des préoccupations de ma classe de modèle est défini dans un ensemble qui n'a pas (et ne devrait pas) l'assemblage System.Web.Mvc de référence. Le réglage personnalisé de liaison (similaire à ) attributs est un non-droit ici.

Autres conseils

vous pouvez modifier le modèle de liaison par défaut à utiliser la culture de l'utilisateur à l'aide IModelBinder

public class DateTimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);

        return value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
    }
}

public class NullableDateTimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);

        return value == null
            ? null 
            : value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
    }
}

Et dans le Global.asax ajouter ce qui suit à Application_Start ():

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

En savoir plus cet excellent blog que expliquer pourquoi l'équipe-cadre Mvc mis en œuvre une culture par défaut à tous les utilisateurs.

J'ai eu moi-même très gros problème et après les heures d'essai et ne parviennent que je suis une solution de travail comme vous avez demandé.

D'abord depuis avoir un liant sur juste une propriété n'est pas possibile yuo doivent mettre en œuvre une ModelBinder complète. Puisque vous ne voulez pas lier tous les biens unique, mais seulement celui que vous vous souciez pouvez hériter de DefaultModelBinder et se lient alors la seule propriété:

public class DateFiexedCultureModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
    {
        if (propertyDescriptor.PropertyType == typeof(DateTime?))
        {
            try
            {
                var model = bindingContext.Model;
                PropertyInfo property = model.GetType().GetProperty(propertyDescriptor.Name);

                var value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);

                if (value != null)
                {
                    System.Globalization.CultureInfo cultureinfo = new System.Globalization.CultureInfo("it-CH");
                    var date = DateTime.Parse(value.AttemptedValue, cultureinfo);
                    property.SetValue(model, date, null);
                }
            }
            catch
            {
                //If something wrong, validation should take care
            }
        }
        else
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }
}

Dans mon exemple, je suis analyse syntaxique date avec une culture fiexed, mais ce que vous voulez faire est possible. Vous devez créer un CustomAttribute (comme DateTimeFormatAttribute) et le mettre sur vous bien:

[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}

dans la méthode bindProperty, au lieu de chercher une propriété DateTime vous pouvez chercher une propriété avec vous DateTimeFormatAttribute, prenez le format que vous avez spécifié dans le constructeur, puis analyser la date avec DateTime.ParseExact

J'espère que cette aide, il m'a fallu beaucoup de temps pour venir avec cette solution. Il était en fait facile d'avoir cette solution une fois que je savais comment chercher le: (

Vous pouvez mettre en œuvre une coutume DateTime Binder comme si, mais vous devez prendre soin de la culture et de la valeur supposée de la demande réelle du client. Pouvez-vous obtenir une date comme mm / jj / aaaa en États-Unis et que vous voulez à convertir dans la culture des systèmes en-GB (ce qui serait comme jj / mm / aaaa) ou une culture invariante, comme nous le faisons, vous doivent analyser avant et utiliser Convert façade statique pour le changer dans son comportement.

    public class DateTimeModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var valueResult = bindingContext.ValueProvider
                              .GetValue(bindingContext.ModelName);
            var modelState = new ModelState {Value = valueResult};

            var resDateTime = new DateTime();

            if (valueResult == null) return null;

            if ((bindingContext.ModelType == typeof(DateTime)|| 
                bindingContext.ModelType == typeof(DateTime?)))
            {
                if (bindingContext.ModelName != "Version")
                {
                    try
                    {
                        resDateTime =
                            Convert.ToDateTime(
                                DateTime.Parse(valueResult.AttemptedValue, valueResult.Culture,
                                    DateTimeStyles.AdjustToUniversal).ToUniversalTime(), CultureInfo.InvariantCulture);
                    }
                    catch (Exception e)
                    {
                        modelState.Errors.Add(EnterpriseLibraryHelper.HandleDataLayerException(e));
                    }
                }
                else
                {
                    resDateTime =
                        Convert.ToDateTime(
                            DateTime.Parse(valueResult.AttemptedValue, valueResult.Culture), CultureInfo.InvariantCulture);
                }
            }
            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
            return resDateTime;
        }
    }

Quoi qu'il en soit, la culture dependend analyse syntaxique DateTime dans une application sans état peut par une cruauté ... Surtout quand vous travaillez avec JSON javascript clientside et en arrière.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top