1.Причина
В соответствии с [FromBody]Time time
в вашем действии, я полагаю, вы отправляете полезную нагрузку с Content-Type
из application/json
.В этом случае при получении полезной нагрузки josn система привязки модели проверит параметр time
и попытается найти для него подходящее связующее.Поскольку context.Metadata.ModelType
равно typeof(Time)
вместо typeof(DateTime)
, а нет пользовательского ModelBinder для typeof(Time)
, ваш метод GetBinder(context)
вернет null
:
public class DateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(DateTime)) // not typeof(Time)
{
return new BinderTypeModelBinder(typeof(DateTime));
}
return null;
}
}
Таким образом, возвращается к связыванию модели по умолчанию для application / json .Связующее по умолчанию для модели json использует Newtonsoft.Json
под капотом и просто десериализует полезную нагрузку отверстия как экземпляр Time
.В результате ваш DateTimeModelBinder
не вызывается.
2.Быстрое исправление
Один из подходов заключается в использовании application/x-www-form-urlencoded
(избегайте использования application/json
)
Удалите атрибут [FromBody]
:
[HttpPost("/test2")]
public IActionResult test2(Time time)
{
return Ok(time);
}
иотправьте полезную нагрузку в формате application/x-www-form-urlencoded
POST https://localhost:5001/test2
Content-Type: application/x-www-form-urlencoded
validFrom=2018-01-01&validTo=2018-02-02
Теперь он должен работать.
3.Работа с JSON
Создайте собственный конвертер, как показано ниже:
public class CustomDateConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public static 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"
};
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var dt= reader.Value;
if (DateTime.TryParseExact(dt as string, _formats, new CultureInfo("en-US"), DateTimeStyles.None, out DateTime dateTime))
return dateTime;
else
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value as string);
}
}
Я просто копирую ваш код для форматирования даты.
Измените свою модель, как показано ниже:
public class Time
{
[ModelBinder(BinderType = typeof(DateTimeModelBinder))]
[JsonConverter(typeof(CustomDateConverter))]
public DateTime? validFrom { get; set; }
[ModelBinder(BinderType = typeof(DateTimeModelBinder))]
[JsonConverter(typeof(CustomDateConverter))]
public DateTime? validTo { get; set; }
}
И теперь вы можете получить время, используя [FromBody]
[HttpPost("/test")]
public IActionResult test([FromBody]Time time)
{
return Ok(time);
}