I get a Date in an ASP.NET Core Controller like this:
public class MyController:Controller{
public IActionResult Test(DateTime date) {
}
}
Had the same problem. While passing DateTime in request body works fine (because Json converter handles this staff), passing DateTime in query string as a parameter has some culture issues.
I did not like the "change all requests culture" approach, bacause this could have impact on other type's parsing, which is not desirable.
So my choise was to override the default DateTime model binding using IModelBinder: https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding
What I did:
1) Define custom binder (c# 7 syntax for 'out' parameter is used):
public class DateTimeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
// Try to fetch the value of the argument by name
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var dateStr = valueProviderResult.FirstValue;
// Here you define your custom parsing logic, i.e. using "de-DE" culture
if (!DateTime.TryParse(dateStr, new CultureInfo("de-DE"), DateTimeStyles.None, out DateTime date))
{
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "DateTime should be in format 'dd.MM.yyyy HH:mm:ss'");
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(date);
return Task.CompletedTask;
}
}
2) Define provider for your binder:
public class DateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(DateTime) ||
context.Metadata.ModelType == typeof(DateTime?))
{
return new DateTimeModelBinder();
}
return null;
}
}
3) And finally, register your provider to be used by ASP.NET Core:
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
});
Now your DateTime will be parsed as expected.