I am trying to apply custom model binder for DateTime type property of model. Here is the IModelBinder and IModelBinderProvider implementations.
public class DateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(DateTime))
{
return new BinderTypeModelBinder(typeof(DateTime));
}
return null;
}
}
public class DateTimeModelBinder : IModelBinder
{
private string[] _formats = new string[] { "yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd"
, "yyyyMMddHHmm", "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm"
, "yyyyMMddHHmmss", "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"};
private readonly IModelBinder baseBinder;
public DateTimeModelBinder()
{
baseBinder = new SimpleTypeModelBinder(typeof(DateTime), null);
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
if (DateTime.TryParseExact(value, _formats, new CultureInfo("en-US"), DateTimeStyles.None, out DateTime dateTime))
{
bindingContext.Result = ModelBindingResult.Success(dateTime);
}
else
{
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, $"{bindingContext} property {value} format error.");
}
return Task.CompletedTask;
}
return baseBinder.BindModelAsync(bindingContext);
}
}
And here is the model class
public class Time
{
[ModelBinder(BinderType = typeof(DateTimeModelBinder))]
public DateTime? validFrom { get; set; }
[ModelBinder(BinderType = typeof(DateTimeModelBinder))]
public DateTime? validTo { get; set; }
}
And here is the controller action method.
[HttpPost("/test")]
public IActionResult test([FromBody]Time time)
{
return Ok(time);
}
When tested, the custom binder is not invoked but the default dotnet binder is invoked. According to the official documentation,
ModelBinder attribute could be applied to individual model properties (such as on a viewmodel) or to action method parameters to specify a certain model binder or model name for just that type or action.
But it seems not working with my code.