Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET mvc 2 - binding a birth date with drop downs

In ASP.NET MVC 2, how would you go about binding a view model property that is a DateTime where the application must have 3 drop down lists for choosing month, day, year?I've read Scott H.'s blog post about binding dates some time ago, and that seems entirely too convoluted for such a simple case. Surely there's a cleaner / better way to do it?

Whatever solution I use, I would like to retain built-in validation using the DataAnnotations stuff, and I'd also like to be able to specify a min / max date range using a validation attribute.

My first thought was a simple custom model binder like so:

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

Then I tried creating a DateTimeAttribute to do the validation, but ran into some difficulty specifying a date range in the attribute declaration because attribute parameter types are limited, and DateTime is not one of the allowable types.

I ended up creating an IDateRangeProvider interface and an implementation specific to birth dates like so:

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

This allowed me to use a DateTime property on my view model and retain all of the build in goodness...

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

But really, the whole solution smells of overengineering and overthinking it. Isn't there a better way?

like image 369
Chris Avatar asked Sep 07 '10 15:09

Chris


1 Answers

create seprate 3 Dropdownlist and add required validation attribute for them.

and use BdateList,BMonthList to populate your DropdownList

[DisplayName("Date of Birth ")]
public DateTime? Birthdate { get; set; }

[Required(ErrorMessage = "Date is required")]
public int BirthDateDate { get; set; }
[Required(ErrorMessage = "Month is required")]
public int BirthDateMonth { get; set; }
[Required(ErrorMessage = "Year is required")]
public int BirthDateYear { get; set; }


public List<System.Web.Mvc.SelectList> BDateList
{
    get
    {
        // create List here

    }
}

and in post method you could assign user selected values values to Model BirthDate

BirthDate.Date.AddDays(BirthDateDate -1).AddMonths(BirthDateMonth)

like image 155
swapneel Avatar answered Dec 23 '22 16:12

swapneel