简体   繁体   English

FormatException:无法从 BsonType 'ObjectId' 反序列化 'Guid'

[英]FormatException: Cannot deserialize a 'Guid' from BsonType 'ObjectId'

I have been going crazy this last days.最近几天我一直在发疯。

I'm trying to use string Guids as _id's in my MongoDb, with the latest version of the driver.我正在尝试使用最新版本的驱动程序在我的 MongoDb 中使用字符串 Guids 作为 _id。 I stumbled with this tutorial, which shed me some light...我偶然发现了这个教程,它让我明白了一些......

Storing GUIDs as strings in MongoDB with C# 使用 C# 在 MongoDB 中将 GUID 存储为字符串

But I am getting this error: FormatException: Cannot deserialize a 'Guid' from BsonType 'ObjectId'.但我收到此错误: FormatException:无法从 BsonType 'ObjectId' 反序列化 'Guid'。

   MongoDB.Bson.Serialization.Serializers.GuidSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
MongoDB.Bson.Serialization.Serializers.SerializerBase<TValue>.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize(IBsonSerializer serializer, BsonDeserializationContext context)
MongoDB.Bson.Serialization.BsonClassMapSerializer<TClass>.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap)

The stack trace:堆栈跟踪:

 at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap)
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeClass(BsonDeserializationContext context)
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
   at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
   at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings)
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateFirstCursorBatch(BsonDocument cursorDocument)
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateCursor(IChannelSourceHandle channelSource, BsonDocument commandResult)
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(IReadBinding binding, CancellationToken cancellationToken)
   at MongoDB.Driver.OperationExecutor.ExecuteReadOperation[TResult](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperation[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperation[TResult](IClientSessionHandle session, IReadOperation`1 operation, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass45_0`1.<FindSync>b__0(IClientSessionHandle session)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.FindFluent`2.ToCursor(CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.AsyncCursorSourceEnumerableAdapter`1.GetEnumerator()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()

I've scoured the Internet in search of an answer.我在网上搜索了答案。

I DO NOT WANT TO USE POCO's DECORATION, OR RETURN BsonDocuments .我不想使用 POCO 的装饰,也不想返回BsonDocuments Already went this route:已经走这条路了:

BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
            BsonSerializer.RegisterSerializer<Guid>(new GuidSerializer(GuidRepresentation.Standard));

and didn't work.并没有工作。 Also did the convention thing...还做了大会的事...

public class GuidAsStringRepresentationConvention : ConventionBase, IMemberMapConvention
    {
        public void Apply(BsonMemberMap memberMap)
        {
            if (memberMap.MemberType == typeof(Guid))
                memberMap.SetSerializer(new GuidSerializer(BsonType.String));
            
            else if (memberMap.MemberType == typeof(Guid?))
                memberMap.SetSerializer(new NullableSerializer<Guid>(new GuidSerializer(BsonType.String)));
        }
    }

Didn't work either...也没用。。。

This is my code:这是我的代码:

public class TestClass
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public bool IsActive { get; set; }
    }

This gets called BEFORE the Db connection:这在 Db 连接之前被调用:

if (!BsonClassMap.IsClassMapRegistered(typeof(TestClass)))
        {
            BsonClassMap.RegisterClassMap<TestClass>(cm =>
            {
                cm.MapIdMember(m => m.Id).SetOrder(0);
                cm.MapMember(m => m.Name).SetOrder(1);
                cm.MapMember(m => m.IsActive).SetOrder(2);
            });
        }

var conn = configuration.GetConnectionString("MongoDb");
            var name = MongoUrl.Create(conn).DatabaseName;
            var client = new MongoClient(conn);
            _db = client.GetDatabase(name); 

after that, I try to get the records, after I initialize the collection in the constructor...之后,我尝试获取记录,在构造函数中初始化集合之后......

public async Task<IEnumerable<TestClass>> ReadAllAsync(CancellationToken cancellationToken = default)
        {
            var filter = Builders<TestClass>.Filter.Empty;
            var items = await _collection.Find<TestClass>(filter).ToListAsync(cancellationToken: cancellationToken);

            return items;
        }

And of course, I initialize the serializer on "ConfigureServices" in the Startup.cs当然,我在 Startup.cs 中的“ConfigureServices”上初始化序列化程序

BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));

Last, the BSON document with the string GUID (or UUID):最后,带有字符串 GUID(或 UUID)的 BSON 文档:

{ 
    "_id" : "c2ea54fc-3942-4ad5-8315-9e96cc5de034", 
    "name" : "I'm Going Crazy", 
    "isActive" : true
}

If anyone can shed some light, I would appreciate it a lot.如果有人能解释一下,我将不胜感激。 Thanks!!!!谢谢!!!!

[UPDATE] [更新]

I did this:我这样做了:

var col = _db.GetCollection<BsonDocument>("TestCollection");
var list = col.Find(FilterDefinition<BsonDocument>.Empty).ToList();

...and I can see the string GUIDs, everything loads perfectly. ...我可以看到字符串 GUID,一切都完美加载。 It's just NOT PARSING correctly.它只是没有正确解析。 AND I DON'T KNOW WHY.我不知道为什么。 And I refuse to parse this document manually!!!!我拒绝手动解析这个文件!!!! That's what the driver is supposed to be doing!这才是司机应该做的!

[UPDATE 2] [更新 2]

Decided to decorate the property with:决定用以下方式装饰该物业:

[BsonId]
[BsonRepresentation(MongoDB.Bson.BsonType.String)]
public Guid Id { get; set; }

Didn't work either...也没用。。。

If you want to keep using Guids natively (rather than treating them as strings), change the serializer you are registering.如果您想继续在本机使用 Guid(而不是将它们视为字符串),请更改您正在注册的序列化程序。

Remove:消除:

BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));

And replace it with:并将其替换为:

BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;

Yes, the second line (at time of writing), is an obsolete method, but for now it's the only way to do it.是的,第二行(在撰写本文时)是一种过时的方法,但目前它是唯一的方法。 It's an open bug with the c# driver .是 c# 驱动程序的开放错误

There does seem to be an issue here that needs to be fixed.这里似乎确实存在需要解决的问题。

In the long run we encourage everyone to use the new V3 GuidRepresentationMode, and in fact when using V3 mode this bug does not appear to happen.从长远来看,我们鼓励大家使用新的 V3 GuidRepresentationMode,事实上,当使用 V3 模式时,这个 bug 似乎不会发生。 I added the following line of code as the first line of main:我添加了以下代码行作为 main 的第一行:

 BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;

We still need to figure out how to get your code to work in V2 mode, but if you are willing to use V3 mode you could have an immediate workaround.我们仍然需要弄清楚如何让您的代码在 V2 模式下工作,但如果您愿意使用 V3 模式,您可以立即找到解决方法。

Apparently, the GUIDs I was using were not valid GUIDs.显然,我使用的 GUID 不是有效的 GUID。 I generated them using an online generator.我使用在线生成器生成它们。

I generated new ones on another website, and voilá.我在另一个网站上生成了新的,瞧。 Everyting worked.一切都奏效了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM