I have a C# v2 Function with an HTTP trigger that looks like this:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] MyParameters parameters,
ILogger log, ExecutionContext context)
The MyParameters class has a DateTime property.
If I run this in Azure and use Postman to POST JSON to it with the DateTime property set to "2019-01-28T13:23:34.12345Z" it works fine.
If I run it locally and use Postman to POST to it with the same value I get the following error:
[23/02/2019 15:33:11] System.Private.CoreLib: Exception while executing function: MyFunction. Microsoft.Azure.WebJobs.Host:
Exception binding parameter 'parameters'. System.Private.CoreLib: String '01/28/2019 13:23:34' was not recognized as a valid DateTime.
Note that the local locale is en-GB - not that that should make a difference to it working.
If I remove the seconds from the DateTime property, i.e. "2019-01-28T13:23" it works locally.
I think this is a runtime issue. It's unable to serialize "2019-01-28T13:23:34.12345Z" as a DateTime if the locale is set to en_GB for some reason.
On Linux to repro:
LANG=en_GB.UTF-8 func start
Investigated 3.0.10 with Newtonsoft.Json 11.0.2
The root of the problem is in the Microsoft.Azure.WebJobs.Extensions.Http.Utility class:
private static object ConvertPropertyValue(JProperty property)
{
if (property.Value != null && property.Value.Type == JTokenType.Object)
{
return (JObject)property.Value;
}
else
{
return (string)property.Value;
}
}
In my example, the incoming JObject property has the following representation {"SubmissionDate": "2019-07-30T09:55:57.5032422+01:00"}, but the else clause yields:
"07/30/2019 09:55:57"
If I ToString() the property value, it yields:
"30/07/2019 09:55:57"
Ergo, the problem appears to be a problem with Newtonsoft.Json.Linq.JToken at v11.0.2, and its explicit string cast operators https://github.com/JamesNK/Newtonsoft.Json/blob/c4af75c8e91ca0d75aa6c335e8c106780c4f7712/Src/Newtonsoft.Json/Linq/JToken.cs#L1224
When I do a simple watch expression on (at time of writing): Convert.ToString(DateTimeOffset.Now, CultureInfo.InvariantCulture), it yields:
07/30/2019 10:35:54 +01:00
Which I guess is correct in the InvariantCulture, but not for my CurrentCulture: en-GB.
Another problem here is the apparent loss of DateTimeOffset precision in the model binding - my en-GB offset is missing in either string conversion. The following returns the result as I _imagine_ I want it:
(DateTimeOffset)property.Value
Which must be leveraging some innate cultural awareness in the DateTimeOffset behaviours, despite also having an invariant culture based explicit cast operator within JToken: https://github.com/JamesNK/Newtonsoft.Json/blob/c4af75c8e91ca0d75aa6c335e8c106780c4f7712/Src/Newtonsoft.Json/Linq/JToken.cs#L508
A simple fix may be an additional branch condition: property.Value.Type == JTokenType.Date.
@alrod this bug seems ... pervasive. Having "worked around it" it in one place ([HttpTrigger]), its reappearing in another binding now.
Having added a model containing a DateTimeOffset to a strong typed IAsyncCollector queue output binding, a subsequent [QueueTrigger] input binding is now throwing the same error.
Any ideas on a way to force the host into an en-US culture when running Func.exe in Windows?
I've checked:
https://docs.microsoft.com/en-us/azure/azure-functions/functions-app-settings https://docs.microsoft.com/en-us/azure/azure-functions/functions-host-json
And there's no mention of locale / culture / language.