Change default format for DateTime parsing in ASP.NET Core

前端 未结 10 1034
情话喂你
情话喂你 2021-02-02 08:57

I get a Date in an ASP.NET Core Controller like this:

public class MyController:Controller{
    public IActionResult Test(DateTime date) {

    }
}
10条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-02-02 09:40

    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.

提交回复
热议问题