protected static void Attach (AnnotationsContext context, IGraphClient graphClient, EntityResolver resolver, EntityConverter converter) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (graphClient == null) { throw new ArgumentNullException(nameof(graphClient)); } if (resolver == null && converter == null) { throw new InvalidOperationException(Messages.NoResolverOrConverterError); } if (resolver != null && converter != null) { throw new InvalidOperationException(Messages.BothResolverAndConverterError); } //if (entityTypes == null || entityTypes.FirstOrDefault() == null) //{ // throw new ArgumentNullException(nameof(entityTypes), "Neo4jClient.DataAnnotations needs to know all your entity types (including complex types) and their derived types aforehand in order to do efficient work."); //} var _converters = graphClient.JsonConverters; if (_converters == null) { _converters = new List <JsonConverter>(); } if (resolver != null) { resolver.AnnotationsContext = context; //EntityResolver = entityResolver; var dummyConverterType = typeof(EntityResolverConverter); if (_converters.FirstOrDefault(c => dummyConverterType.IsAssignableFrom(c.GetType())) is EntityResolverConverter existingConverter) { _converters.Remove(existingConverter); } graphClient.JsonContractResolver = resolver; //add a dummy converter that just proxies entityresolver deserialization //we do this because neo4jclient currently doesn't use ContractResolvers at deserialization, but they use converters. _converters.Add(resolver.DeserializeConverter); } if (converter != null) { converter.AnnotationsContext = context; //EntityConverter = entityConverter; var entityConverterType = typeof(EntityConverter); if (_converters.FirstOrDefault(c => entityConverterType.IsAssignableFrom(c.GetType())) is EntityConverter existingConverter) { _converters.Remove(existingConverter); } //we may have to mix this two (resolver and converter) eventually because of some choices of the neo4jclient team. //entityConverter._canRead = true; _converters.Add(converter); } if (_converters.Count > 0 && graphClient.JsonConverters != _converters) //!= existingConverters?.Length) { try { //try reflection to set the converters in the original array Utils.Utilities.GetBackingField(graphClient.GetType() .GetProperty("JsonConverters", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) .SetValue(graphClient, _converters); } catch { } } if (graphClient is IBoltGraphClient) { if (!graphClient.IsConnected) { //connection is required at this point for bolt clients throw new InvalidOperationException(Messages.ClientIsNotConnectedError); } dynamic driverMemberInfo = null; var driverProperty = graphClient .GetType() .GetProperty("Driver", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); if (driverProperty != null && !driverProperty.CanWrite) { FieldInfo driverBackingField = null; try { //try reflection to set the driver via backing field driverBackingField = Utils.Utilities.GetBackingField(driverProperty); driverMemberInfo = driverBackingField; } catch { } } else { driverMemberInfo = driverProperty; } var driver = driverMemberInfo?.GetValue(graphClient) as IDriver; if (driver == null) { //this isn't supposed to happen throw new InvalidOperationException(Messages.ClientHasNoDriverError); } //now wrap the driver with our wrappers driver = new DriverWrapper(driver); try { //replace the driver driverMemberInfo?.SetValue(graphClient, driver); } catch { } } }