Before sharing some code, let’s first talk about what we are trying to achieve. By default, the DateTime binding mechanism does not work with custom date formats. So in this post, we are going to implement a method of resolving this using a custom binding mechanism, which is easier than you might think.
Resolving binding issues with culture variants
When we talk about custom date formats, we don’t mean formats which are not native to the default US locale. For example, in the UK where I am, we can set our applications culture, with something like this.
var localeOptions = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo> { new ("en-GB") },
SupportedUICultures = new List<CultureInfo> { new ("en-GB") },
DefaultRequestCulture = new RequestCulture("en-GB")
};
app.UseRequestLocalization(localeOptions);
One thing to be aware of there is that this works fine for model binding, but data passed through as a query string, then the default culture is only used for model binding, data coming from the query string is the invariant culture.
Building a custom model binder
In my application, I have a need to look at dates which are in the format of yyyyMMdd, easy enough to parse from this format, or format to this, when working with the DateTime type, but if you are performing model binding, say on a request in a Web API, then you will get some errors.
First off, we need to create a custom DateTimeModelBinder and a DateTimeModelBinderAttribute, here is the code for doing this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
For the GetModelName method, the “name” property of the ModelBinder attribute is used to specify the route parameter name when the action parameter name is different from the route parameter name. For example, when the route is /api/{endDate} and the action parameter name is date.
We can add this attribute with a Name property as follows: [DateTimeModelBinder(Name = "endDate")].
Next, we also need a helper method, the code for this is as follows.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Finally, as I want to bind to model properties, I also need a CustomDateTimeConverter, here is the final piece of code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
We are now able to pull all of this together, so on our model property, we can use the JsonConverter attribute from Newtonsoft.Json, and provide the following.
[JsonConverter(typeof(CustomDateTimeConverter), ["yyyyMMdd"])]
public DateTime UsageDateTime { get; set; }
Summary
There you have it, don’t forget, if your problem is based around the culture your application is running, use that rather than implement something custom, but if you need to work with specific formats, you can now use a custom date time model binder.
Hi there! My name is Martyn Coupland. I'm a Microsoft Azure and DevOps transformation specialist, Microsoft MVP, Certified Trainer, author and speaker based in England. It’s nice to meet you.
View all posts by Martyn Coupland