Я хотел бы записать свой собственный образцовый редактор связей для DateTime
ввести. В первую очередь, я хотел бы записать новый атрибут, как который я могу присоединить к своему свойству модели:
[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}
Это - легкая часть. Но часть редактора связей является немного более трудной. Я хотел бы добавить новый образцовый редактор связей для типа DateTime
. Я могу также
IModelBinder
соедините интерфейсом и запишите мое собственное BindModel()
методDefaultModelBinder
и переопределение BindModel()
методМоя модель имеет свойство, как замечено выше (Birth
). Таким образом, когда модель пытается связать, запрашивают данные к этому свойству, мой образцовый редактор связей BindModel(controllerContext, bindingContext)
вызывается. Все хорошо, но. Как я получаю атрибуты свойства от controller/bindingContext, для парсинга моей даты правильно? Как я могу добраться до PropertyDesciptor
из свойства Birth
?
Из-за разделения проблем мой образцовый класс определяется в блоке, который не делает (и не был должен), ссылочная Система. Сеть. Блок MVC. Установка пользовательской привязки (подобный примеру Scott Hanselman) атрибуты является остановкой здесь.
Я не думаю, что вам следует помещать в модель атрибуты, специфичные для конкретной местности.
Два других возможных решения этой проблемы:
Чтобы ответить на ваш вопрос, способ получить пользовательские атрибуты (для MVC 2) - написать AssociatedMetadataProvider.
У меня самого была эта очень большая проблема, и после нескольких часов попыток и неудач я получил рабочее решение, как вы и просили.
Прежде всего, поскольку привязка только к свойству невозможна, вы должны реализовать полноценный ModelBinder. Поскольку вы не хотите связывать все свойства, а только то, которое вам важно, вы можете наследовать от DefaultModelBinder и затем связать одно свойство:
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);
}
}
}
В моем примере я разбираю дату с фиксированной культурой, но то, что вы хотите сделать, возможно. Вы должны создать CustomAttribute (например, DateTimeFormatAttribute) и поместить его над вашим свойством:
[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}
Теперь в методе BindProperty вместо того, чтобы искать свойство DateTime, вы можете искать свойство с вашим DateTimeFormatAttribute, взять формат, который вы указали в конструкторе, а затем разобрать дату с помощью DateTime.ParseExact
Надеюсь, это поможет, у меня ушло очень много времени, чтобы прийти к этому решению. На самом деле это решение было простым, как только я понял, как его искать :(