Skip to content

Instantly share code, notes, and snippets.

@martyncoup
Last active April 29, 2024 14:30
Show Gist options
  • Save martyncoup/74bc803ce0dd21d00b8ca93f5749def6 to your computer and use it in GitHub Desktop.
Save martyncoup/74bc803ce0dd21d00b8ca93f5749def6 to your computer and use it in GitHub Desktop.
public class DateTimeModelBinder : IModelBinder
{
public static readonly Type[] SupportedTypes = [typeof(DateTime), typeof(DateTime?)];
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
if (!SupportedTypes.Contains(bindingContext.ModelType))
{
return;
}
var modelName = GetModelName(bindingContext);
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var dateToParse = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(dateToParse))
{
return;
}
var dateTime = ParseDate(bindingContext, dateToParse);
bindingContext.Result = ModelBindingResult.Success(dateTime);
await Task.CompletedTask;
}
private DateTime? ParseDate(ModelBindingContext bindingContext, string dateToParse)
{
var attribute = GetDateTimeModelBinderAttribute(bindingContext);
var dateFormat = attribute?.DateFormat;
if (string.IsNullOrEmpty(dateFormat))
{
return Helper.ParseDateTime(dateToParse);
}
return Helper.ParseDateTime(dateToParse, new string[] { dateFormat });
}
private DateTimeModelBinderAttribute GetDateTimeModelBinderAttribute(ModelBindingContext bindingContext)
{
var modelName = GetModelName(bindingContext);
var paramDescriptor = bindingContext.ActionContext.ActionDescriptor.Parameters
.Where(x => x.ParameterType == typeof(DateTime?))
.Where((x) =>
{
// See comment in GetModelName() on why we do this.
var paramModelName = x.BindingInfo?.BinderModelName ?? x.Name;
return paramModelName.Equals(modelName);
})
.FirstOrDefault();
if (!(paramDescriptor is ControllerParameterDescriptor ctrlParamDescriptor))
{
return null;
}
var attribute = ctrlParamDescriptor.ParameterInfo
.GetCustomAttributes(typeof(DateTimeModelBinderAttribute), false)
.FirstOrDefault();
return (DateTimeModelBinderAttribute)attribute;
}
private string GetModelName(ModelBindingContext bindingContext)
{
if (!string.IsNullOrEmpty(bindingContext.BinderModelName))
{
return bindingContext.BinderModelName;
}
return bindingContext.ModelName;
}
}
public class DateTimeModelBinderAttribute : ModelBinderAttribute
{
public string DateFormat { get; set; }
public DateTimeModelBinderAttribute()
: base(typeof(DateTimeModelBinder))
{
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment