简体   繁体   English

.NET Core 中的 Mongo C# 驱动程序和 ObjectID JSON 字符串格式

[英]Mongo C# Driver and ObjectID JSON String Format in .NET Core

Problem问题

I have a collection of dynamic data.我有一组动态数据。 I want to get it back like this:我想像这样取回它:

{
  _id: "58b454f20960a1788ef48ebb"
  ... 
}

Attempts尝试

Here are a list of approaches that do not work:以下是不起作用的方法列表:

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources);

Yields产量

[[{"name":"_id","value":{"bsonType":7,"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z","rawValue":{"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z"},"value":{"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z"}}}]]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources.ToJson());

Yields产量

[{ "_id" : ObjectId("58b454f20960a1788ef48ebb"), ... }]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources.ToJson(new JsonWriterSettings() { OutputMode = JsonOutputMode.Strict }));

Yields产量

[{ "_id" : { "$oid" : "58b454f20960a1788ef48ebb" }, ... }]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(resources));

Yields产量

"Newtonsoft.Json.JsonSerializationException: Error getting value from 'AsBoolean' on 'MongoDB.Bson.BsonObjectId'. ---> System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonObjectId' to type 'MongoDB.Bson.BsonBoolean' “Newtonsoft.Json.JsonSerializationException:从“MongoDB.Bson.BsonObjectId”上的“AsBoolean”获取值时出错。---> System.InvalidCastException:无法将“MongoDB.Bson.BsonObjectId”类型的对象转换为“MongoDB.Bson” .BsonBoolean'

And changing BsonDocument to dynamic yields the same results.BsonDocument更改为dynamic产生相同的结果。

I have also tried registering a serializer according to the docs .我还尝试根据文档注册序列化程序。 I really like this solution since I always want my ObjectId s in a reasonable format and not in something unusable.我真的很喜欢这个解决方案,因为我总是希望我的ObjectId具有合理的格式,而不是无法使用的格式。 I would like to get this working if possible.如果可能的话,我想让这个工作。

This

_client = new MongoClient(clientSettings); 
_database = _client.GetDatabase(_settings.DatabaseName); 
BsonSerializer.RegisterSerializer(new ObjectIdSerializer());

...

class ObjectIdSerializer : SerializerBase<ObjectId>
{
    public override ObjectId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return context.Reader.ReadObjectId();
    }

    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ObjectId value)
    {
        context.Writer.WriteString(value.ToString());
    }
}

Had no effect on any of the above results.对上述任何结果都没有影响。

Use BsonDocument when saving to MongoDB保存到 MongoDB 时使用 BsonDocument

After trying a number of different configurations, the only way I was able to correctly save truly dynamic documents using the connector was to parse objects as BsonDocument s.在尝试了许多不同的配置之后,我能够使用连接器正确保存真正动态文档的唯一方法是将对象解析为BsonDocument

public ActionResult Post([FromBody]JObject resource)
{
    var document = BsonDocument.Parse(resource.ToString(Formatting.None));

    DbContext.Resources.InsertOne(document);
}

Register BsonDocument serializers with JSON.Net使用 JSON.Net 注册BsonDocument序列化程序

The problem with the above approach initially was that when calling ToJson() the ISODate and ObjectId objects would be serialized into objects, which was undesirable.上述方法最初的问题是,在调用ToJson()ISODateObjectId对象将被序列化为对象,这是不可取的。 At the time of writing, there doesn't seem to be any extensibility points for overriding this behavior.在撰写本文时,似乎没有任何可覆盖此行为的扩展点。 The logic is baked into the MongoDB.Bson.IO.JsonWriter class , and you cannot register BsonSerializer s for BsonValue types:该逻辑被烘焙到MongoDB.Bson.IO.JsonWriter类中,并且您不能为BsonValue类型注册BsonSerializer

MongoDB.Bson.BsonSerializationException: A serializer cannot be registered for type BsonObjectId because it is a subclass of BsonValue. MongoDB.Bson.BsonSerializationException:无法为类型 BsonObjectId 注册序列化程序,因为它是 BsonValue 的子类。

At the time of writing, the only solution I've found is to explicitly custom JSON.Net converters.在撰写本文时,我发现的唯一解决方案是显式自定义 JSON.Net 转换器。 MongoDB C# Lead Robert Stam has created an unpublished library for this which community member Nathan Robinson has ported to .net-core. MongoDB C# 负责人 Robert Stam为此创建了一个未发布的库,社区成员 Nathan Robinson 已将其移植到 .net-core。 . . I've created a fork that properly serializes the ObjectId and ISODate fields.我创建了一个正确序列化 ObjectId 和 ISODate 字段的分支。

I've created a NuGet package from their work.我从他们的工作中创建了一个 NuGet 包。 To use it, include the following reference in your .csproj file:要使用它,请在.csproj文件中包含以下引用:

<PackageReference Include="MongoDB.Integrations.JsonDotNet" Version="1.0.0" />

Then, explicitly register the converters:然后,显式注册转换器:

Startup.cs启动文件

using MongoDB.Integrations.JsonDotNet.Converters;

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddJsonOptions(options =>
        {
            // Adds automatic json parsing to BsonDocuments.
            options.SerializerSettings.Converters.Add(new BsonArrayConverter());
            options.SerializerSettings.Converters.Add(new BsonMinKeyConverter());
            options.SerializerSettings.Converters.Add(new BsonBinaryDataConverter());
            options.SerializerSettings.Converters.Add(new BsonNullConverter());
            options.SerializerSettings.Converters.Add(new BsonBooleanConverter());
            options.SerializerSettings.Converters.Add(new BsonObjectIdConverter());
            options.SerializerSettings.Converters.Add(new BsonDateTimeConverter());
            options.SerializerSettings.Converters.Add(new BsonRegularExpressionConverter());
            options.SerializerSettings.Converters.Add(new BsonDocumentConverter());
            options.SerializerSettings.Converters.Add(new BsonStringConverter());
            options.SerializerSettings.Converters.Add(new BsonDoubleConverter());
            options.SerializerSettings.Converters.Add(new BsonSymbolConverter());
            options.SerializerSettings.Converters.Add(new BsonInt32Converter());
            options.SerializerSettings.Converters.Add(new BsonTimestampConverter());
            options.SerializerSettings.Converters.Add(new BsonInt64Converter());
            options.SerializerSettings.Converters.Add(new BsonUndefinedConverter());
            options.SerializerSettings.Converters.Add(new BsonJavaScriptConverter());
            options.SerializerSettings.Converters.Add(new BsonValueConverter());
            options.SerializerSettings.Converters.Add(new BsonJavaScriptWithScopeConverter());
            options.SerializerSettings.Converters.Add(new BsonMaxKeyConverter());
            options.SerializerSettings.Converters.Add(new ObjectIdConverter());
        }); 
    }
}

Now, you can serialize using the default serializer:现在,您可以使用默认序列化程序进行序列化:

return Created($"resource/{document["_id"].ToString()}", document);

You can make your last attempt work by registering custom ObjectIdConverter with NewtonSoft.您可以通过向 NewtonSoft 注册自定义ObjectIdConverter来完成最后一次尝试。

await resources = _database.GetCollection<dynamic>("resources")
    .Find(Builders<dynamic>.Filter.Empty)
    .ToListAsync();

return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(resources, new ObjectIdConverter()));

Converter:转换器:

class ObjectIdConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value.ToString());

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(ObjectId).IsAssignableFrom(objectType);
    }
}

Note: The above converter converts from ObjectId to String after the BSONSerailzers have converted bson value to ObjectId .注意:从上述转换器转换ObjectId到字符串后BSONSerailzers具有转换后的BSON值ObjectId

You'll still need to use parse to convert string id to ObjectIds for queries and register the ObjectIdConverter globally.您仍然需要使用 parse 将字符串 id 转换为 ObjectIds 以进行查询并全局注册 ObjectIdConverter。

Reference: https://stackoverflow.com/a/16693462/2683814参考: https : //stackoverflow.com/a/16693462/2683814

A "terrible" way of solving this is to convert your BsonDocument to a Dictionary in case your object is a plain object.解决此问题的“可怕”方法是将您的 BsonDocument 转换为字典,以防您的对象是普通对象。

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var items = (await collection.Find(new BsonDocument()).ToListAsync());

        var obj = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(items.ToJson());

        return Ok(obj);
    }

This method is simple to code but I see a lot of overhead for conversions.这种方法易于编码,但我看到很多转换开销。

The best way is to change the Asp.Net serializer to return the "items.ToJson()" as the response Content without trying to parse it.最好的方法是更改​​ Asp.Net 序列化程序以返回“items.ToJson()”作为响应内容而不尝试解析它。

The old (but gold) HttpRequestMessage enables it.旧的(但黄金) HttpRequestMessage 启用它。 (I can't have time to create a sample to share here now) (我现在没有时间创建一个样本在这里分享)

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

相关问题 Mongo C# 驱动程序和 ObjectID JSON 字符串格式 - Mongo C# Driver and ObjectID JSON String Format MongoDB C#驱动程序 - 将字符串列表表示为ObjectId列表 - MongoDB C# Driver - Representing a list of string as list of ObjectId 在带有 C# 的点网核心中使用带有 mongo 驱动程序的过滤器时如何忽略大小写 - How to ignore case when using filters with the mongo driver in dot net core with C# Model class通过.Net core c#中日期格式转换为JSON字符串 - Convert Model class to JSON string by converting date format in .Net core c# 使用C#mongo驱动程序执行复杂的mongo JSON查询 - Execute complex mongo JSON query using C# mongo driver C# 网芯 Odata web api json 格式异常 - C# net core Odata web api json format exception 如何在 Z2D50972FCECD70612895456 中使用 C# mongo Db 驱动程序将多个文档组合/合并到一个 c# object - How to combine/merge multiple document to one c# object using C# mongo Db driver in .net core 在.NET Core上调用Mongo的C#驱动程序时无法加载类型&#39;System.Runtime.Remoting.Messaging.CallContext&#39; - Could not load type 'System.Runtime.Remoting.Messaging.CallContext' when calling into Mongo's C# Driver on .NET Core 使用字符串、整数数组反序列化 json - .net 核心 C# - Desserialize json with string,int array - .net core C# 在 C# Linq 驱动程序中查询 MongoDB 'ObjectId' - Query MongoDB 'ObjectId' in C# Linq Driver
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM