Как в ASP.NET MVC 2 связать свойство модели представления, представляющее собой DateTime, где у приложения должно быть 3 раскрывающихся списка для выбора месяца, дня и года? Я читал Скотта Х. сообщение в блоге об обязательных датах некоторое время назад, и это кажется слишком запутанным для такого простого случая. Конечно, есть более чистый / лучший способ сделать это?
Какое бы решение я ни использовал, я бы хотел сохранить встроенную проверку с использованием материала DataAnnotations, а также хотел бы иметь возможность указать минимальный / максимальный диапазон дат с помощью атрибута проверки.
Моей первой мыслью было простое пользовательское связующее для модели:
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
{
var model = bindingContext.Model as RsvpViewModel;
var form = controllerContext.HttpContext.Request.Form;
if (model == null)
throw new ArgumentException("bindingContext.Model");
if (propertyDescriptor.Name.Equals("BirthDate"))
{
if (!string.IsNullOrEmpty(form["BirthYear"]) &&
!string.IsNullOrEmpty(form["BirthMonth"]) &&
!string.IsNullOrEmpty(form["BirthDay"]))
{
try
{
var yy = int.Parse(form["BirthYear"]);
var mm = int.Parse(form["BirthMonth"]);
var dd = int.Parse(form["BirthDay"]);
model.BirthDate = new DateTime(yy, mm, dd);
return;
}
catch (Exception)
{
model.BirthDate = DateTime.MinValue;
return;
}
}
}
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
Затем я попытался создать атрибут DateTimeAttribute для проверки, но столкнулся с некоторыми трудностями при указании диапазона дат в объявлении атрибута, поскольку типы параметров атрибута ограничены, а DateTime не является одним из допустимых типов.
Я закончил тем, что создал интерфейс IDateRangeProvider и реализацию, специфичную для дат рождения, например:
public interface IDateRangeProvider
{
DateTime GetMin();
DateTime GetMax();
}
public class BirthDateRangeProvider : IDateRangeProvider
{
public DateTime GetMin()
{
return DateTime.Now.Date.AddYears(-100);
}
public DateTime GetMax()
{
return DateTime.Now.Date;
}
}
Это позволило мне использовать свойство DateTime в моей модели представления и сохранить все сборки в совершенстве ...
[DisplayName("Date of Birth:")]
[Required(ErrorMessage = "Date of birth is required")]
[DateTime(ErrorMessage = "Date of birth is invalid", RangeProvider=typeof(BirthDateRangeProvider))]
public DateTime? BirthDate { get; set; }
Но на самом деле весь раствор пахнет чрезмерной инженерией и переосмыслением. Разве нет лучшего способа?