2

I am currently building a form that requires the user to enter their date of birth. I have determined that the most user friendly way to do this is through separate date day, month, and year input fields.

I have a strongly typed view that contains text boxes for birth day, birth month, and birth year. Once the form is posted to the server I require these posted string values to be converted to a proper DateTime object. I am currently generating this DateTime object in my custom validator that performs age validation tests however I believe there is a far better approach.

So far I have tried building the DateTime object in the model constructor as follows:

public class Applicant
{
    [Required(ErrorMessage = "Day Required")]
    public string DobDay { get; set; }
    [Required(ErrorMessage = "Month Required")]
    public string DobMonth { get; set; }
    [Required(ErrorMessage = "Year Required")]
    [BirthDateValidation("DobDay", "DobMonth")]
    public string DobYear { get; set; }

    public DateTime BirthDate { get; set; }

    public Applicant()
    {
        this.BirthDate = new DateTime(Convert.ToInt32(this.DobYear), Convert.ToInt32(this.DobMonth), Convert.ToInt32(this.DobDay));
    }
}

Is there a way to make this task more automated, as I have tried above, so that when the form is posted to the server a DateTime object is automatically built using the posted birth day, birth month, birth year form values?

CodeMonkey
  • 119
  • 4
  • 12
  • Your constructor wont work with model binding. You can create a custom ModelBinder to read the form data and build your DateTime property. –  Mar 23 '16 at 10:09
  • What do you mean by _more automated_? And why don't you define those properties as an `int` instead of `string`? – Soner Gönül Mar 23 '16 at 10:09
  • possibly a bad choice of words but I was looking for a way for the constructor to generate the DateTime object however according to the Stephen this is possible. – CodeMonkey Mar 23 '16 at 10:16

1 Answers1

1

Use a custom model binder:

public class MyCustomBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
                            ModelBindingContext bindingContext)
    {
        HttpRequestBase request = controllerContext.HttpContext.Request;

        string day = request.Form.Get("DobDay");
        string month = request.Form.Get("DobMonth");
        string year = request.Form.Get("DobYear");
        //etc..
        return new Applicant
        {
            BirthDate = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day))
            //etc..
        };
    }
}

[HttpPost]
public ActionResult Save([ModelBinder(typeof(MyCustomBinder))] Applicant applicant)
{
    return View();
}
James Dev
  • 2,979
  • 1
  • 11
  • 16
  • Looks promising although this looks like it will only work for one DateTime. I will have multiple DateTime is there a way to do this for all Dates without duplicating the above code? – CodeMonkey Mar 23 '16 at 10:21
  • Of course where you return the Applicant model class you can populate as many properties as you want. So you can have as many dates as you wish if they are on the model. The custom model binder is just a layer between the form values and the controller so you can do your logic there. – James Dev Mar 23 '16 at 10:32
  • [This old post](http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx) by Scott Hanselman helped a lot – galdin Aug 17 '16 at 17:25