Custom model binder for a property
override BindProperty and if the
property is "PropertyB" bind the
property with my custom binder
That's a good solution, though instead of checking "is PropertyB" you better check for your own custom attributes that define property-level binders, like
[PropertyBinder(typeof(PropertyBBinder))]
public IList<int> PropertyB {get; set;}
You can see an example of BindProperty override here.
Apply Custom Model Binder to Object Property in asp.net core
1. Reason
According to the [FromBody]Time time
in your action, I guess you're sending a payload with Content-Type
of application/json
. In that case, when a json payload received, the Model Binding System will inspect the parameter time
and then try to find a proper binder for it. Because the context.Metadata.ModelType
equals typeof(Time)
instead of the typeof(DateTime)
, and there's no custom ModelBinder for typeof(Time)
, your GetBinder(context)
method will return a 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;
}
}
Thus it falls back to the default model binder for application/json. The default json model binder uses Newtonsoft.Json
under the hood and will simply deserialize the whole payload as an instance of Time
. As a result, your DateTimeModelBinder
is not invoked.
2. Quick Fix
One approach is to use application/x-www-form-urlencoded
(avoid using the application/json
)
Remove the [FromBody]
attribute:
[HttpPost("/test2")]
public IActionResult test2(Time time)
{
return Ok(time);
}
and send the payload in the format of 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
It should work now.
3. Working with JSON
Create a custom converter as below :
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);
}
}
I simply copied your code to format the date.
Change your Model as below :
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; }
}
And now you can receive the time using [FromBody]
[HttpPost("/test")]
public IActionResult test([FromBody]Time time)
{
return Ok(time);
}
Related Topics
Setup Database (Sqlite) for Unity
How to Write Out a Text File in C# with a Code Page Other Than Utf-8
Dynamically Select Columns in Runtime Using Entity Framework
Is the Destructor Called If the Constructor Throws an Exception
Xamarin Android Alarm Manager Issue
Is There Pointer in C# Like C++? Is It Safe
How to Display a List of Images, from a Folder on Hard Drive, on ASP.NET Website
Feasibility of C# Development with Mono
Androidapp and MySQL connection Didn't Work Connection.Open
Getting a Request.Headers Value
Is There a Tool for Finding Unreferenced Functions (Dead, Obsolete Code) in a C# App
Linq-To-Sql: Recursively Get Children
Deserialize JSON Object Sent from Android App to Wcf Webservice
Creating Safe SQL Statements as Strings
How to Share Sessions Between PHP and ASP.NET Application
String.Format Alternative in C++
Encryption Compatible Between Android and C#
Signalr Owin Self-Host on Linux/Mono Socketexception When Clients Lose Connection