22

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

trailmax
  • 34,305
  • 22
  • 140
  • 234
  • Have you already come across these two https://github.com/aspnet/Localization/issues/136, http://www.jerriepelser.com/blog/how-aspnet5-determines-culture-info-for-localization/ – Nkosi Jun 22 '17 at 02:23
  • Also `yyyy/MM/dd` always work. if all else fails. – Nkosi Jun 22 '17 at 02:25
  • @Nkosi all the dance with `CurrentCulture` and `CurrentUiCulture` does not seem to make any difference on dates binding. I might go down the path of the second format you mention – trailmax Jun 22 '17 at 13:26
  • @Nkosi yeah, got it sorted - I got myself confused first, but after unpeeling all the layers it worked. – trailmax Jun 22 '17 at 13:36
  • Can you add how you eventually got it working as a self answer. I am interested. – Nkosi Jun 22 '17 at 13:42
  • @Nkosi Answer below is what I've used. Plus I had to adjust culture on a js-side of the app - it was adding to the confusion. – trailmax Jun 22 '17 at 14:50
  • 1
    "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'm guessing that you got the part after "i.e." mixed up. – Ergwun Mar 13 '18 at 10:37

3 Answers3

26

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/

MindingData
  • 11,924
  • 6
  • 49
  • 68
  • Thanks for looking into this. I've tried your suggestions, read through the article. Indeed my registration initially was in the wrong place. I've moved it above all MVC related registrations and it did not change a thing. These cultures don't seem to affect the way MVC binds the dates on requests. – trailmax Jun 22 '17 at 13:12
  • Aaahhh... and it is working. Got a bit confused with the dates - once cleared all the surrounding stuff out of the way - I got the dates bound correclty. – trailmax Jun 22 '17 at 13:35
  • I am using Net Core with Nginx on Debian. When I start directly on command line using `dotnet app.dll` the date works fine on POST, but when I start the application as a systemd service, the format changes. This answer worked for me just fine, with `CultureInfo("pt-BR")`. – Pablo Sep 27 '18 at 14:27
  • This works for me, I'm using net6, got confused when DateTime value from BodyRequest always converted to dd/MM/yyyy HH.mm.ss , but format that I need is en-GB format => HH:mm:ss – Konsultan IT Bandung Jan 26 '22 at 08:15
22

Updated answer for aspnet core 2.0

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        var supportedCultures = new[] { new CultureInfo("es-CO") };
        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture("es-CO"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        });

        // other configurations after (not before)
    }
iojancode
  • 610
  • 6
  • 7
  • 2
    This worked for me ASP.NET Core 3.1. Thanks! It's a pity that the DataFormatString that is specified in DisplayFormat in the model object is not respected with ApplyFormatInEditMode=true when binding. – phn Feb 28 '20 at 14:38
2

Just in case anyone else comes across this question as I did, with an issue specifically around when the date is supplied in a HTTP Get query string.

If you supply the dates in a query string, culture configurations in the startup are ignored, even when specified as the only accepted.

The ASP.NET Core route value provider and query string value provider: Treat values as invariant culture. Expect that URLs are culture-invariant. In contrast, values coming from form data undergo a culture-sensitive conversion. This is by design so that URLs are shareable across locales.

You can see a workaround in the Microsoft docs here:

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-6.0#globalization-behavior-of-model-binding-route-data-and-query-strings-1

ajbeaven
  • 9,265
  • 13
  • 76
  • 121
David Moores
  • 1,025
  • 2
  • 9
  • 23
  • The link points to a great bit of documentation that is very hard to find. Thanks for increasing its visibility. – ajbeaven Sep 06 '22 at 02:31