MongoFramework icon indicating copy to clipboard operation
MongoFramework copied to clipboard

Custom Entity Serializer

Open Turnerj opened this issue 4 years ago • 4 comments

Continuing from the ideas of #87 , it is probably worthwhile to make a custom entity serializer that uses the EntityDefinition rather than BsonClassMap. Every type that gets an entity definition would automatically get this new serializer applied to it and all of its properties.

While I don't have any specific numbers at the moment, I think there is a good chance to squeeze a lot better performance while lowering allocations.

Ultimately this would still need to use the BsonSerializerRegistry and be otherwise compatible with the default serializer system in the MongoDB driver.

First, this should start with a benchmark of the current serialization system to see what we are dealing with.

Turnerj avatar Oct 29 '19 00:10 Turnerj

One thing I'm interested in is actually seeing if I could leverage System.Text.Json as the bulk of the serialization logic instead. It would make working with the driver's built-in systems difficult and JSON != BSON however there still might be ways it can perform really well in this setup.

Turnerj avatar Feb 27 '21 00:02 Turnerj

While looking into a different issue, I stumbled across the BsonClassMapSerializationProvider and BsonClassMapSerializer<TClass> - it is effectively these two classes I'd be replicating but using my entity definition. These classes are fairly isolated however the BsonClassMapSerializationProvider is registered and acts somewhat greedy in terms of serialization. I can't just add my serialization registration to the end as it will still go through the BsonClassMapSerializationProvider.

private static void CreateSerializerRegistry()
{
    __serializerRegistry = new BsonSerializerRegistry();
    __typeMappingSerializationProvider = new TypeMappingSerializationProvider();

    // order matters. It's in reverse order of how they'll get consumed
    __serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider());
    __serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider());
    __serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider());
    __serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider());
    __serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider());
    __serializerRegistry.RegisterSerializationProvider(__typeMappingSerializationProvider);
    __serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider());
}

I will need to use reflection and "inject" my provider before it. It is backed by a private ConcurrentStack so it is gonna be messy. I need to keep it there as MongoFramework shouldn't clobber the library - there should be a way to trigger this initialization on assembly load automatically so the user doesn't need to bother configuring it.

Turnerj avatar Sep 12 '21 14:09 Turnerj

@Turnerj, How is work moving along on this one ? Is there something I can help with ?

bobbyangers avatar Jan 14 '22 12:01 bobbyangers

Haven't been able to work on this more yet myself.

The first, most important part is identifying how much performance the serializer is currently leaving on the table. Need to establish a benchmark for how well the existing one works - allocations and throughput. The benchmark needs to isolate the BsonClassMapSerializer<TClass> as that is the core part we are effectively replacing. We need to instantiate it and call its serialize/deserialize methods etc.

Then it is a matter of prototyping a custom serializer on the same example model and seeing how much faster it can be made using entity definitions. We'd still be serializing to BsonDocument etc but it is the process of serializing to/from it that we would be changing.

Turnerj avatar Jan 15 '22 03:01 Turnerj