Search code examples
c#.netmongodbserializationmongodb-.net-driver

Custom serilization of a complex C# object using simple objects


I am using a utility class from QuickGraph called AdjacencyGraph that has a complex internal structure.

I do not care for all the internal properties of the complex class and I cant change it as its from a nuget package - at most in my database I am just concerned in storing an array of Dependency objects that can be used to reconstruct the AdacencyGraph:

public class Dependency
{
    public Dependency(string source, string target)
    {
        this.Source = source;
        this.Target = target;
    }

    public string Source { get; set; }
    public string Target { get; set; }
}

On serialization, all i need to do is the following code:

void Serialize(Dependencies toSerialize)
{
    var toBeStored = toSerialize.GetAllDependencies();
    // write this to mongodb somehow
}

And deserialization build the Dependencies object:

Dependencies Deserialize(IEnumerable<Dependency> hydrateFrom)
{
    var dependencies = new Dependencies();

    foreach(var d in hydrateFrom)
    {
        dependencies.SetRequiresFor(d.Source, d.Target);
    }
}

Question

How would I go about intercepting the serialization process and output?

Other Information

I have wrapped the AdjacencyGraph around in a class that lists all Dependency objects, and can accept a list of Dependency objects too.

class Dependencies
{
    private AdjacencyGraph<string, Edge<string>> relationshipGraph = new AdjacencyGraph<string, Edge<string>>();

    public void SetRequiresFor(SkuId on, SkuId requires)
    {
        var toAdd = new Edge<string>(on.Value, requires.Value);
        this.relationshipGraph.AddVerticesAndEdge(toAdd);

    }

    public IEnumerable<Dependency> GetAllDependencies()
    {
        foreach(var edge in this.relationshipGraph.Edges)
        {
            yield return new Dependency(edge.Source, edge.Target);
        }
    }
}

Solution

  • There are 3 things you need to do:

    1. Implement a BsonSerializer.
    2. Implement a BsonSerializationProvider that will point Dependencies to your serializer.*
    3. Register the provider in your application's initialization.

    BsonSerializer

    public class DependenciesBsonSerializer : BsonBaseSerializer
    {
        public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
        {
            // implement using bsonWriter
        }
    
        public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
        {
            // implement using bsonReader
        }
    }
    

    BsonSerializationProvider

    public sealed class BsonSerializationProvider : IBsonSerializationProvider
    {
        public IBsonSerializer GetSerializer(Type type)
        {
            if (type == typeof(Dependncies)
            {
                return new DependenciesBsonSerializer ();
            }
    
            return null;
        }
    }
    

    Registeration

    BsonSerializer.RegisterSerializationProvider(new BsonSerializationProvider());
    

    * You could cut the provider and register the serializer directly using BsonSerializer.RegisterSerializer but I still recommend grouping all your serializers in a single provider.