Frage

Ich möchte mein eigenes Modell Bindemittel für DateTime Art schreiben. Zunächst einmal möchte ich ein neues Attribut schreiben, dass ich zu meinem Modell Eigenschaft anhängen können wie:

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

Das ist der einfache Teil. Aber das Bindemittel Teil ist ein bisschen schwieriger. Ich möchte ein neues Modell Bindemittel für Typ DateTime hinzuzufügen. Ich kann entweder

  • IModelBinder-Schnittstelle implementieren und meine eigene BindModel() Methode schreiben
  • vererben DefaultModelBinder und Überschreibung BindModel() Methode

hat mein Modell eine Eigenschaft, wie oben (Birth) gesehen. Also, wenn das Modell versucht zu binden Anforderungsdaten dieser Eigenschaft wird mein Modell Binder BindModel(controllerContext, bindingContext) aufgerufen. Alles in Ordnung, aber. Wie erhalte ich Eigenschaft Attribute von Controller / Binding, mein Datum zu analysieren richtig ? Wie kann ich auf die PropertyDesciptor der Immobilie Birth bekommen?

Bearbeiten

Aufgrund der Trennung von Bedenken meine Modellklasse ist in einer Baugruppe definiert, die nicht der Fall ist (und sollte nicht) Referenz System.Web.Mvc Montage. Einstellen von benutzerdefinierter Bindung (ähnlich Scott Hanselman Beispiel ) Attribute ist ein no-go hier.

War es hilfreich?

Lösung

Ich glaube nicht, Sie locale-spezifische Attribute auf einem Modell setzen sollten.

Zwei weitere mögliche Lösungen für dieses Problem sind:

  • Haben Sie Ihre Seiten transkribieren stammt aus dem locale-spezifischen Format in ein generisches Format wie yyyy-mm-dd in JavaScript. (Works, aber benötigt JavaScript.)
  • Schreiben Sie ein Modell Bindemittel, das die aktuelle UI-Kultur hält, wenn Daten Parsen.

Ihre eigentliche Frage zu beantworten, die Art und Weise benutzerdefinierte Attribute zu erhalten (für MVC 2) ist auf ein AssociatedMetadataProvider schreiben.

Andere Tipps

können Sie den Standardbinder Modell ändern, um den Benutzer Kultur mit IModelBinder verwenden

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);
    }
}

Und in dem Global.asax fügen Sie die folgende zu Application_Start ():

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

Lesen Sie mehr unter diesem ausgezeichnete Blog dass beschreiben, warum MVC-Framework-Team eine Standard Kultur für alle Benutzer implementiert.

Ich hatte dieses sehr großes Problem selbst und nach Stunden von Versuch und scheitern Ich habe eine Arbeitslösung wie Sie gefragt.

Vor allem, da nur auf eine Eigenschaft einen Bindemittels ist nicht possibile yuo hat einen vollen Modelbinder zu implementieren. Da Sie nicht den bind alles einzelne Eigenschaft wollen aber nur die eine Pflege, Sie von Default erben und dann binden die einzelne Eigenschaft:

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);
        }
    }
}

In meinem Beispiel ich Parse Datum mit einer fiexed Kultur, aber was wollen Sie tun, ist möglich. Sie sollten eine CustomAttribute (wie DateTimeFormatAttribute) erstellen und legte es über Sie Eigenschaft:

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

Jetzt im bindProperty Methode, statt für ein DateTime- Eigenschaft suchen Sie können DateTimeFormatAttribute mit Ihnen für eine Immobilie suchen, das Format greifen Sie im Konstruktor angegeben und dann das Datum parsen mit DateTime.ParseExact

Ich hoffe, das hilft, es hat mich sehr lange mit dieser Lösung zu kommen. Es war eigentlich einfach, diese Lösung zu haben, sobald ich wusste, wie es zu suchen: (

Sie können eine benutzerdefinierte Datetime-Binder wie so implementieren, aber Sie müssen sich um über die angenommener Kultur und Wert von der aktuellen Client-Anfrage. Können Sie ein Datum wie mm / tt / in en-US und wollen bekommen es in dem System Kultur en-GB (was es sein würde wie tt / mm / jjjj) oder eine invariante Kultur konvertieren, wie wir es tun, Ihnen dann müssen sie analysieren, bevor und mit Hilfe der statischen Fassade wandelt es in seinem Verhalten zu ändern.

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

Wie auch immer, Kultur abhängige Datetime-Analyse in einer stateless Anwendung kann durch eine Grausamkeit ... Vor allem, wenn Sie mit JSON arbeiten Javascript client und rückwärts.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top