Elfocrash / Cosmonaut

🌐 A supercharged Azure CosmosDB .NET SDK with ORM support
https://cosmonaut.readthedocs.io
MIT License
341 stars 44 forks source link

JsonSerializerSettings in CosmosStoreSettings #80

Closed michellesong2 closed 5 years ago

michellesong2 commented 5 years ago

I am adding JsonSerializerSettings property to CosmosStoreSettings, and then call AddAsync(obj) to save obj to Cosmos db. For example,

In the Startup.cs file:

CosmosStoreSettings _cosmosStoreSettings = new CosmosStoreSettings("dbname", endpoint, authKey);

        var serializerSettings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            DateFormatHandling = DateFormatHandling.IsoDateFormat,
            DateParseHandling = DateParseHandling.DateTimeOffset,
            DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
            TypeNameHandling = TypeNameHandling.None,
        };

        serializerSettings.Converters.Add(new StringEnumConverter());
        serializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "o" });

        _cosmosStoreSettings.JsonSerializerSettings = serializerSettings;

        services.AddCosmosStore<Student>(_cosmosStoreSettings);

In my repository file: var response = await CosmosStore.AddAsync(obj);

Student object 'obj' is saved to cosmos db, but the serializerSettings is not applied. I could see serializerSettings is included in CosmosStore by dependency injection.

I did a POC by using DocumentClient directly, and set the JsonSerializerSettings in the DocumentClient constructor, and then it works. So just wonder why it doesn't work through Cosmonaut.

Elfocrash commented 5 years ago

This is very bizarre and looking at the code I can't see why that would happen. Can you please also provide the Student class so I can debug it?

Thanks

michellesong2 commented 5 years ago

using System; using System.Collections.Generic; using System.Text; using Newtonsoft.Json; using Cosmonaut.Attributes;

namespace CosmosPocService.Shared { [CosmosCollection("mycollection")] public class Student { [JsonProperty("id")] public string Id { get; set; }

    [JsonProperty(PropertyName = "lastModified")]
    public DateTimeOffset? LastModified { get; set; }
}

}

The above is the Student class. The LastModified property is not saved to cosmos db correctly via the JSON serializer settings.

Elfocrash commented 5 years ago

@michellesong2 Hey, I finally got some time to look into this.

What would be an acceptable example and what's what you're getting instead?

It looks like you want ISO 8601 which is what I'm getting with your code: 2019-04-13T17:17:09.7572072+00:00. If I change "o" to "d" I am getting "13/04/2019" as expected.

Am I missing something?

michellesong2 commented 5 years ago

Yes. That’s what I want but it didn’t happen that way. Thank you very much for looking into this.

On Apr 13, 2019, at 1:22 PM, Nick Chapsas notifications@github.com wrote:

@michellesong2 Hey, I finally got some time to look into this.

What would be an acceptable example and what's what you're getting instead?

It looks like you want ISO 8601 which is what I'm getting with your code: 2019-04-13T17:17:09.7572072+00:00

Am I missing something?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

HMoen commented 5 years ago

I was going to open a new issue, but I seem the be having the same issue as @michellesong2 that the JSON serializer settings are not being respected. Maybe related to https://github.com/Azure/azure-cosmos-dotnet-v2/issues/351 (Their suggestion of adding it as the default settings works)

My JSON serializer settings are the following:

var serializerSettings = new JsonSerializerSettings
{
  ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
  NullValueHandling = NullValueHandling.Ignore,
  TypeNameHandling = TypeNameHandling.Auto,
  Formatting = Formatting.Indented,
  ////MissingMemberHandling = MissingMemberHandling.Error,
};
serializerSettings.Converters.Add(new StringEnumConverter(true));

Side note: If MissingMemberHandling is uncommented, following serializer exception is thrown:

Could not find member 'ResourceKey' on object of type 'Client'. Path 'ResourceKey', line 1, position 296.

I instantiate a CosmosStore in the following manner:

var policy = new ConnectionPolicy {  ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp };
var documentClient = new DocumentClient(endpoint, key, serializerSettings, policy);
var cosmonautClient = new CosmonautClient(documentClient);
var store = new CosmosStore<TDocument>(cosmonautClient, databaseName);
store.Settings.JsonSerializerSettings = serializerSettings;

When a document is stored, it won't convert enums to its string value and won't ignore properties with null values, for example. Any advice on this?

Thank you in advance for your time.

Elfocrash commented 5 years ago

@HMoen I closed this since I wasn't able to recreate it. The provided code was working as expected. Which Cosmonaut version are you using and could you please provide me with a link of a sample project having this issue?

Thanks

HMoen commented 5 years ago

@Elfocrash here you go:

  1. Version: 2.10.0
  2. https://github.com/HMoen/CosmonautFunctionApp

I tried to mimic as close as possible to our configuration with a .NET Standard class and an AF. The function project contains CosmosStorageExplorerCapture.JPG which is a snapshot detailing the non-converted enum and the null value not being ignored.

HMoen commented 5 years ago

@Elfocrash, have you had a chance to look at the repo? This solution worked for me https://github.com/Azure/azure-cosmos-dotnet-v2/issues/351, even though prefer not to have global settings. Is it safe to assume this is a CosmosDB issue? Possibly the AF runtime is overriding it.

Elfocrash commented 5 years ago

@HMoen This is an issue of the underlying SDK indeed. I meant to reply but I forgot, sorry.

There is nothing I can do other than wait for them to fix it since Cosmonaut is a wrapper around the v2 SDK.