result.ContentAs<T>(); not using parameterized constructor to create object

All of my classes use private setters, simplified example:

public class Person {
    public string PersonId { get; private set:}
    public string FirstName { get; private set;}
    public string LastName { get; private set;} 
    
   public Person(string id, string firstName, string lastName) {
         Id= id;
         FirstName = firstName;
         LastName = lastName;
  }
}

Everything persists perfectly fine, but when I retrieve my document the constructor on my object is not being called to hydrate my object:

 public async Task<Person> GetByIdAsync(string id)
    {
        using var result = await _collection.GetAsync(id);
        var person = result.ContentAs<Person>();
       
        return person;
    }

I know I am getting my document back properly, I tested:

var doc = result.ContentAs<string>();

And it contained the proper document and the correct data but result.ContentAs<Person>(); just returns an object with empty strings for values.

I tried adding [JsonConstructor] annotation on my class I saw in another post along with the following configuration for my cluster:

 var serializerSettings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto,
        NullValueHandling = NullValueHandling.Ignore
    };
    serializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
    
    var options = new ClusterOptions
    {
        UserName = "username",
        Password = "password",
    };
    options.ApplyProfile("wan-development");
    
    options.WithSerializer(
        new DefaultSerializer(serializerSettings, serializerSettings)
    );
        
    var cluster = await Cluster.ConnectAsync(
        "couchbases://cb.mycluster.cloud.couchbase.com",
        options
    );

No luck, anyone solve this issue?

I am coming from MongoDB after they killed Atlas yesterday and I have a TON of things to migrate and I would love to avoid writing a ton of mappers or calling constructors manually everywhere if possible.

@engineering

Your most likely difficultly is where you were already looking, the JsonConstructor attribute. This indicates to the JSON deserializer which constructor to use to create the class when deserializing.

In your example, you are using the DefaultSerializer that is implemented using Newtsonsoft.Json. If I had to make a guess, you may have put the wrong JsonConstructor attribute. Make sure you are using the attribute from the Newtonsoft.Json namespace and not the one from System.Text.Json.Serialization.

The other possibility is some interaction around parameter names versus the actual content of your JSON documents.

On a side note, for new projects that don’t have legacy serialization needs, I generally recommend using the System.Text.Json serializer rather than Newtonsoft.Json, as it’s more performant.

1 Like

Thank you sir!

I did not notice I had my streams crossed, IDE auto import usings got me.

I really appreciate the fast feedback and help.

See answer from @btburnett3 - I had bad serializer configuration issue.

Thanks

1 Like