Search code examples
c#model-bindingunobtrusive-validationdate-formattingasp.net-mvc-5.2

Date Format EN-AU Not accepting dd/mm/yyyy Client-side and Server-Side


I have several pages which use jquery UI date pickers for my viewmodel datetime properties. Here is my viewmodel:

public class UsageFilterViewModel : BaseModel
{
    [Display(Name="Entity Name")]
    public string EntityName { get; set; }
    public string UserLogin { get; set; }
    public int[] SelectedQuestionGroup { get; set; }
    public IEnumerable<SelectListItem> QuestionGroups { get; set; }
    [Display(Name = "Date From"), DataType(DataType.DateTime)]
    public DateTime? DateFrom { get; set; }
    [Display(Name = "Date To"), DataType(DataType.DateTime)]
    public DateTime? DateTo { get; set; }
    [Display(Name="Exclude IP")]
    public string ExcludeIP { get; set; }
    public string URL { get; set; }
}

My view:

@using (Html.BeginForm(null, null, FormMethod.Get, new { @class = "form-horizontal", @id = "formfilter" }))
{
    @Html.AntiForgeryToken()
    <input type="hidden" value="True" name="Display" />
    <table class="table table-condensed table-responsive table-hover smart-form">
    <tr>
        <th>Entity Name</th>
        <td>@Html.TextBoxFor(m => m.EntityName, new { @style = "width: 75px" })</td>
        <th>User Login</th>
        <td>@Html.TextBoxFor(m => m.UserLogin, new { @style = "width: 75px" })</td>
        <th>Question Group</th>
        <td>@Html.ListBoxFor(m => m.SelectedQuestionGroup, Model.QuestionGroups, new { @class = "select2", @multiple = "multiple" })</td>
    </tr>
    <tr>
         <th>From</th>
         <td>
             <div class="input-group" style="width:100px;">
             @Html.TextBoxFor(m=>m.DateFrom, Model.DateFrom.HasValue ? Model.DateFrom.Value.ToShortDateString() : null, new { @placeholder = "From", @style = "width: 75px" })
             <span class="input-group-addon"><i class="fa fa-calendar"></i></span>

             @Html.TextBoxFor(m=>m.DateTo, Model.DateTo.HasValue ? Model.DateTo.Value.ToShortDateString() : null, new { @placeholder = "To", @style = "width: 75px" })
              <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
              </div>
          </td>
          <th>Exclude IP</th>
          <td>@Html.TextBoxFor(m => m.ExcludeIP, new { @style = "width: 75px" })</td>
          <th>URL</th>
          <td>@Html.TextBoxFor(m => m.URL, new { @style = "width: 75px" })</td>
      </tr>
   </table>
   <div class="widget-footer">
       @Html.ValidationSummary(false, null, new { @class = "alert alert-warning fade in" })
       <button class="btn btn-info" type="submit">Display</button>
   </div>
}

My javascript that creates the datepickers:

$(document).ready(function () {
    $("#DateFrom").datepicker({
        changeMonth: true,
        changeYear: true,
        numberOfMonths: 3,
        dateFormat: 'dd/mm/yy',
        prevText: '<i class="fa fa-chevron-left"></i>',
        nextText: '<i class="fa fa-chevron-right"></i>',
        onClose: function (selectedDate) {
            $("#DateTo").datepicker("option", "minDate", selectedDate);
        }

    });
    $("#DateTo").datepicker({
        changeMonth: true,
        changeYear: true,
        numberOfMonths: 3,
        dateFormat: 'dd/mm/yy',
        prevText: '<i class="fa fa-chevron-left"></i>',
        nextText: '<i class="fa fa-chevron-right"></i>',
        onClose: function (selectedDate) {
            $("#DateFrom").datepicker("option", "maxDate", selectedDate);
        }
    });
});

On the client-side: the validation is passing when I enter a date such as '21/04/2015', and the datepicker is creating dates in the correct format. Therefore the page is posting back.

On the server-side: the validation is failing.

ModelState.IsValid = false

When the view renders, the Html.ValidationSummary renders this:

The value '20/04/2015' is not valid for Date From. The value '21/04/2015' is not valid for Date To.

As per this explanation, my Web.Config explicitly sets the culture to EN-AU:

<system.web>
    <globalization uiCulture="en-AU" culture="en-AU" enableClientBasedCulture="false" />
</system.web>

I have tried this solution, but with the same result.

The request-headers for the HTTP request are:

Accept-Language:en-GB,en;q=0.8

I can get the client-side working by overriding the jquery ui date format:

$.validator.methods.date = function (value, element) {
    var dateRegex = /^(0?[1-9]\/|[12]\d\/|3[01]\/){2}(19|20)\d\d$/;
    return this.optional(element) || dateRegex.test(value);
};

Also,

@System.Threading.Thread.CurrentThread.CurrentCulture returns "en-AU"

It seems that by setting the culture in the Web.config, it should accept that format for dates, currency, etc.

How can I get it working for dd/mm/yyyy both client and server-side?

I will also be introducing globalisation in the future, so I want the solution to be ready for other locales.


Solution

  • The solution to this is to use the HTTP POST method instead of GET, as per: this answer. It is not an ideal solution, because sometimes I want to submit forms using the GET method to submit back to the same action.

    I would like to overwrite the GetHttpHandler like this, but without using and displaying anything in the Routes.