How to set culture for date binding in Asp.Net Core?

trailmax picture trailmax · Jun 22, 2017 · Viewed 21.3k times · Source

I have an Asp.Net Core application with MVC. I'm submitting a form with a date on the form.

Form looks (roughly) like this:

@model EditCustomerViewModel
<form asp-action="Edit">
    <input asp-for="ServiceStartDate" class="form-control" type="date" />
    <input type="submit" value="Update" class="btn btn-success" />
</form>

Controller action is:

[HttpPost]
public async Task<IActionResult> Edit(EditCustomerViewModel viewModel)
{
    // do stuff
    return RedirectToAction("Index");
}

View model is:

public class EditCustomerViewModel
{
    public Guid Id { get; set; }

    [DataType(DataType.Date)]
    public DateTime ServiceStartDate { get; set; }

    [DataType(DataType.Date)]
    public DateTime? ServiceEndDate { get; set; }

    // etc.
}

I'm in the UK, so dates are not in US format: dd/MM/YYYY. So by default I'm submitting 6/22/2017.

When looking on the submitted view model in controller during debugging, dates are null if submitted in UK format, but are fine if using US format. i.e. 6/22/2017 gives me null, but 22/6/2017 is bound to the correct date.

I have tried adding this to Startup.cs but it did not make any difference:

var supportedCultures = new[] { new CultureInfo("en-GB") };
app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture("en-GB"),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures
});
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-GB");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-GB");
CultureInfo.CurrentCulture = new CultureInfo("en-GB");
CultureInfo.CurrentUICulture = new CultureInfo("en-GB");

I've checked HTTP headers and I'm posting correct header:

Accept-Language: en-GB,en

What am I doing wrong? How can I tell MVC Core binders to bind dates in UK format?

p.s. I'm on VS2017 with *.csproj project file, with target framework .NetCoreApp 1.1

Answer

MindingData picture MindingData · Jun 22, 2017

A couple of things. I'm not sure you can push a new settings object into the middleware like that (You probably can), but most of the time I have seen it used in the ConfigureServices method like so :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RequestLocalizationOptions>(options =>
    {
        options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en-NZ");
        options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("en-NZ") };
    });

    services.AddMvc();
}

Second. The order of your middleware is very important. Ensure that your call to UseRequestLocalization happens before UseMvc. Infact it should probably be the first thing in your pipeline unless there is a specific reason it can't be.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseRequestLocalization();
    app.UseMvc();
}

And finally, can you try removing all the providers from the pipeline (One of which is a cookie provider. I can't fathom why you would have this cookie but let's just try).

In your configure method call clear on the RequestCultureProviders list. This should ensure that there is nothing else there to set a culture.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RequestLocalizationOptions>(options =>
    {
        options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en-GB");
        options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-GB") };
        options.RequestCultureProviders.Clear();
    });

    services.AddMvc();
}

More info : http://dotnetcoretutorials.com/2017/06/22/request-culture-asp-net-core/