2.0 DP3 Question on Views / JsonDataMapper.cs Deserialization

Hi,

I wonder a little about the intended usage of the Query method. I would assume that T is my own class the returned view data is deserialized into. But the Json returned on the respons stream encapsulates my view data in a property called “value”. For this to work I must use a “row” wrapper like:

[DataContract]
public class ViewResultRow<T>
{
	[DataMember(Name = "id")]
	public string ID
	{
		get;
		set;
	}

	[DataMember(Name = "key")]
	public object Key
	{
		get;
		set;
	}

	[DataMember(Name = "value")]
	public T Value
	{
		get;
		set;
	}
}

and do my call like bucket.Query<ViewResultRow<MyClass>>("blah") or I must change my class.

If this is by design I would prefer if we can change the IDataMapper to a custom implementation that can implement a custom JsonContractResolver.

Being at this point my next issue is that the DeserializationSettings from the ClientConfiguration class are ignored in JsonDataMapper.cs. I would like to suggest passing the ClientConfiguration to the JsonDataMapper class and change the Map(Stream stream) code to something like:

public T Map<T>(Stream stream)
    {
        T instance;
        using (var streamReader = new StreamReader(stream))
        {
			instance = JsonConvert.DeserializeObject<T>(streamReader.ReadToEnd(), _clientConfig.DeserializationSettings);
			//using (var jsonReader = new JsonTextReader(streamReader))
			//{
			//	instance = _serializer.Deserialize<T>(jsonReader);
			//}
        }
        return instance;
    }

The required changes would be:
Cluster.cs -> CreateManager

return new ClusterManager(Configuration, _clusterController, new HttpClient(), new JsonDataMapper(Configuration), username, password);

Server.cs -> CTOR

public Server(IOStrategy ioStrategy, Node node, ClientConfiguration clientConfiguration, IBucketConfig bucketConfig) :
        this(ioStrategy,
		new ViewClient(new HttpClient(), new JsonDataMapper(clientConfiguration), bucketConfig, clientConfiguration),
		new QueryClient(new HttpClient(), new JsonDataMapper(clientConfiguration)),
        node, clientConfiguration)
    {
    }

CouchbaseBucket.cs -> CreateManager

return new BucketManager(Name, _configInfo.ClientConfig, _clusterManager, new HttpClient(), new JsonDataMapper(_configInfo.ClientConfig), username, password);

Maybe I got the whole idea wrong but currently this design looks incomplete to me. Someone who can enlighten me on this?

coboluxx -

Thanks for the feedback; as it is in DP3 you would need to do as you specified or use a dynamic object, but this will change for GA. We are planning to refactor how the whole serialization component works so that the client doesn’t dependency on any specific JSON serializer and to make it easier to provide custom implementations such as this.

Thanks,

Jeff

Hi Jeff,

thanks for the feedback. But I think it is important to note that the current implementation may kill existing documents. It is always using the CamelCasePropertyNamesContractResolver no matter what you have set on the client configurations serialization settings. If you have used the DefaultDataContractResolver previously the document may get serialized with wrong property name casing with the current implementation.

I think the DefaultTranscoder.cs should get the ClientConfiguration and use the serializer settings from there. The constructor with incomingSerializerSettings and outgoingSerializerSettings is IMHO useless as the serialization settings may change after an instance of Cluster was created (if you are using configuration based settings and modifying the serialization settings after creating the Cluster() instance.

Changing the constructor to read
public DefaultTranscoder(IByteConverter converter, ClientConfiguration configuration)
{
_converter = converter;
_clientConfiguration = configuration;
}
requires only a few changes to the code.

Maybe this would make the current code more useful for testing until the refactoring of the whole serialization story is completed.

Thanks,
Marcus