How exactly to use a custom json serializer with NEST on .net


(George Mauer) #1

Hi all, I was directed here by the Elasticsearch NEST client for .Net (really well written by the way).

I'm hitting a bit of a wall and the docs are too sparse on how exactly to do this.

Basically, my objects have private setters and I want deserialization to work anyways.

I'm aware that I can use NEST.JsonNetSerializer and that with this I seem to be able to pass in a sourceSerializer factory parameter into my ConnectionSettings which in turn can have the jsonSerializerSettingsFactory but from there things don't seem to work.

static ConnectionSettings settings = new ConnectionSettings (
    new SingleNodeConnectionPool(new Uri("http://localhost:9200")), 
    sourceSerializer: (builtin, settings) => {
	var serializer =new JsonNetSerializer(builtin, settings, jsonSerializerSettingsFactory: () => {
	   return new Newtonsoft.Json.JsonSerializerSettings {
		   ContractResolver = new Ducky(),	   	
	   };
	});
	return serializer;
})
static ElasticClient client = new ElasticClient(settings);

public class Ducky : DefaultContractResolver {
	protected override List<MemberInfo> GetSerializableMembers(Type objectType) {
		return objectType.GetMembers(BindingFlags.NonPublic | BindingFlags.Public).ToList();
	}
}

When I do this and then make a query, a breakpoint inside of GetSerializableMembers never seems to get hit and my properties with private setters are not populated. I'm not certain what else to do.


(Russ Cam) #2

The breakpoint does not get hit because the ContractResolver property on JsonSerializerSettings is always assigned to in a private method:

There's no easy way to change the IContractResolver right now, not at least without duplicating a lot of the code within ConnectionSettingsAwareSerializerBase. This is because IContractResolver can be modified but not assigned to, and the reasoning behind this was to hide the complexity behind the resolver needing knowledge of the connection settings.

One way in which private members can be serialized easily is by attributing with JsonPropertyAttribute

private static void Main()
{
	var defaultIndex = "products";
    
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    var settings = new ConnectionSettings(pool, JsonNetSerializer.Default)
        .DefaultIndex(defaultIndex);
    var client = new ElasticClient(settings);

    client.IndexDocument(new Product("foo")
    {   
       Id = 1       
    });
}

public class Product
{
    [JsonProperty]
    private string Name;

    public Product(string name)
    {
        Name = name;
    }
    
    public int Id { get; set; }
}

which will serialize to

{
  "name": "foo",
  "id": 1
}

(George Mauer) #3

I'm not sure I understand...what is the point of being able to provide your own json serializer if you can't make changes to the contract resolver? That's really the only part of the serializer settings I've ever been interested in. What other sort of stuff do people use that nuget package for?

Going in and annotating tons of domain-model properties with attributes that are all about json which isn't even a domain concept just goes again all my DDD instincts.

Is this something that might be a good candidate for a PR? The ability to use private setters shouldn't be considered out there, its pretty standard practice when you want to enforce validity on your domain objects. I wouldn't imagine implementing this would require all that much work, it should be possible to wrap the ConnectionSettingsAwareSerializer in a decorator or something...


(George Mauer) #4

Also, I just tried adding [JsonProperty] to public properties with a private setter and it didn't deserialize...


(system) #5

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.