Guid serialization with C#/.NET Driver 2.14.1 seems to be different for insert and find/update/replace

Hallo people,
We have a MongoDB 5.0.5 Community Server installed here and we are writing our software with .NET 5 using the current version of the MongoDB .NET Driver.
As we had some trouble using Guids with MongoDB, I built a very simple test app that shows the problem:

using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using System;
using System.Threading.Tasks;

namespace GuidTestMongoDB
{
    internal class Program
    {
        class Sample
        {
            [BsonGuidRepresentation(GuidRepresentation.Standard)]
            public Guid Id { get; set; }
            public int SomeData { get; set; } = 42;
        }

        static async Task Main(string[] args)
        {
            BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
            MongoClient mongoDBClient = new("...");
            IMongoDatabase database = mongoDBClient.GetDatabase("...");
            IMongoCollection<Sample> testCollection = database.GetCollection<Sample>("testing");

            Guid guid = Guid.NewGuid();
            // the insert call works fine
            await testCollection.InsertOneAsync(new Sample { Id = guid }).ConfigureAwait(false);

            // test find
            Sample sample = await testCollection.Find(Builders<Sample>.Filter.Eq(c => c.Id, guid)).FirstOrDefaultAsync().ConfigureAwait(false);
            // -> sample is null !!!

            // test upsert
            guid = Guid.NewGuid();
            await testCollection.ReplaceOneAsync(Builders<Sample>.Filter.Eq(p => p.Id, guid), new Sample { Id = guid }, new ReplaceOptions { IsUpsert = true }).ConfigureAwait(false);
            // -> throws an exception:
            // A write operation resulted in an error. WriteError: { Category : "Uncategorized", Code : 66, Message : "After applying the update, the (immutable) field '_id' was found to have been altered to _id: UUID("ef571d0d-a345-4ed3-b867-41a6dc2d6476")" }.
        }
    }
}

As noted in the code, we cannot find the entry we just inserted by using exactly the same Id. The upsert code throws an exception with the shown error message.

I also tried to update another Guid field and found the following:

  • After inserting the Guid ‘ef571d0d-a345-4ed3-b867-41a6dc2d6476’ MongoDB Compass Community shows the value: Binary(‘71cdDaNFTtO4Z0Gm3C1kdg==’)
  • After updating this field with exactly the same Guid I get: Binary(‘DR1X70Wj0064Z0Gm3C1kdg==’)

Obviously the Guid is serialized differently. What do we do wrong? Is there a Bug in the .NET Driver?

Thanks,
Hagen

Historically the C# driver attempted to enforce that all Guids in the same collection were serialized using the same representation, and the default representation was CSharpLegacy.

Over time it became apparent that was not the best choice, and that it would often be the case that different Guid fields in the same collection might be serialized differently.

Working with Guids in the original design (now called GuidRepresentationMode.V2) was very difficult to get right, as you have discovered trying to get your code sample working.

The easiest solution for you is to simply switch to the new design (called GuidRepresentationMode.v3).

To opt-in to the GuidRepresentationMode.V3 mode add the following line at the beginning of your program:

BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;

and also annotate every Guid class member with the desired representation (as you have already done).

Documentation for Guid Serialization is here:

http://mongodb.github.io/mongo-csharp-driver/2.14/reference/bson/guidserialization/

Thanks for your explanation.
We did not use this GuidRepresentationMode as it is marked obsolete, so we thought using the standard serialization mode is the way to work with Guids. Anyway, using GuidRepresentationMode.V3 solves the issues, although it generates the obsolete warning (which we can switch off of course).

Thank you very much,
Hagen