You can do this with the existing serializers but it requires a small amount of configuration.
Assume the following class:
public class C
{
public int Id { get; set; }
public Dictionary<long, long> D { get; set; }
}
You can configure a custom serializer for the D property (the Dictionary) that uses a key serializer that serializes longs to strings. The code would look like this:
BsonClassMap.RegisterClassMap<C>(cm =>
{
cm.AutoMap();
var customDictionarySerializer = new DictionaryInterfaceImplementerSerializer<Dictionary<long, long>>(
dictionaryRepresentation: DictionaryRepresentation.Document,
keySerializer: new Int64Serializer(BsonType.String),
valueSerializer: BsonSerializer.SerializerRegistry.GetSerializer<long>());
cm.GetMemberMap(c => c.D).SetSerializer(customDictionarySerializer);
});
The key idea here is that even though the keys and values are both longs, we are using different serializers for the keys and the values.
If we then run a quick test:
var document = new C { Id = 1, D = new Dictionary<long, long> { { 2, 3 } } };
var json = document.ToJson();
Console.WriteLine(json);
We see that the Dictionary keys are now being serialized as strings:
{ "_id" : 1, "D" : { "2" : NumberLong(3) } }