2
votes

I ran into some difficulties storing a DateTime object given as a string in CosmosDB. To make sure it's not related to serialization of DateTime objects, I'm currently working with strings only.

My stored document in the database looks as follows:

{
    "available": true,
    "id": "391a802c-ac42-443b-860a-8ab7061b389c",
    "checked_date": "2020-06-04T12:53:29.4625341Z",
    "code": "AAAA",
    "_rid": "w6VGAOSKaJABAAAAAAAAAA==",
    "_self": "dbs/w6VGAA==/colls/w6VGAOSKaJA=/docs/w6VGAOSKaJABAAAAAAAAAA==/",
    "_etag": "\"00000000-0000-0000-3a70-96abc3ea01d6\"",
    "_attachments": "attachments/",
    "_ts": 1591275829
}

I'm using a very simple function to query it:

[FunctionName("GetObject")]
public static async Task<IActionResult> GetObject(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "object/{code}")] HttpRequest req,
    [CosmosDB(
        databaseName: "database01",
        collectionName: "objecttable",
        ConnectionStringSetting = "CosmosDBString",
        SqlQuery = "SELECT c.id, c.code, c.available, c.checked_date FROM objecttable c WHERE LOWER(c.code)=LOWER({code})")] IEnumerable<ObjectEntity> entities,
                ILogger log)
{
    log.LogInformation("GetObject function processed a request.");
    return new JsonResult(entities);
}

The ObjectEntity class looks like this:

[JsonObject(MemberSerialization.OptIn)]
public class ObjectEntity
{
    [JsonProperty(PropertyName = "available")]
    public bool Available {get; set;}

    [JsonProperty(PropertyName = "id")]
    public string Id {get; set;}

    [JsonProperty(PropertyName = "checked_date")]
    public string CheckedDate {get; set;}

    [JsonProperty(PropertyName = "code")]
    public string Code{get; set;}
}

When storing some arbitrary string data in the field "checked_date", the string just gets returned as expected. When I store a string like "2020-06-04T12:53:29.4625341Z", I get "06/04/2020 12:53:29" returned instead - without applying any deserialization, typecasting or something similar.

Using the CosmosDB Explorer, I see the correct string representation.

This is not related to the return object of the Azure function, the problem occurs within the function already. If I set a breakpoint within the function I can see that the strings in the entities object are already messed up.

What am I doing wrong here? Is the CosmosDB binding messing up my string here?


Update: I've set the CosmosDB connection mode to "Direct" and traced the request using Fiddler. It seems that CosmosDB does indeed return the correct string in the response body:

{"_rid":"w6VGAOSKaJA=","Documents":[{"id":"391a802c-ac42-443b-860a-8ab7061b389c","code":"AAAA","available":true,"checked_date":"2020-06-04T12:53:29.4625341Z"}],"_count":1}

So the issue has to be related to the binding itself or the deserialization?

1

1 Answers

2
votes

That is probably related to the SDK using the default Newtonsoft.Json serializer settings which parse strings to datetime (https://github.com/Azure/azure-cosmos-dotnet-v2/issues/235 and https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_DateParseHandling.htm), DateParseHandling.None would solve it.

The bindings do not let you define how the DocumentClient is initialized sadly. One alternative would be to maintain your own instance instead of using the binding (which I guess is more code in the end). DocumentClient has a constructor that let's you specify an instance of JsonSerializerSettings.

Make sure the instance is created following the Functions' guidelines.

Another alternative would be to set it globally but that would affect all the other code that is using Newtonsoft.Json: Json.net global settings

Finally, you could create a custom converter over the property that just outputs the text as-is.