C#结合MongoDB时,如何更新包含JObject的POCO对象并解决序列化异常问题?
This is a common pitfall when mixing MongoDB's default serialization with Newtonsoft.Json's JObject/JArray types. Let's break down why this happens and walk through actionable fixes:
The core issue is that MongoDB's C# driver treats JObject and JArray as regular .NET objects by default. During serialization, it adds type discriminator fields (_t and _v) to track the exact .NET type. When deserializing, the driver tries to reconstruct these types using this discriminator data, which clashes with how Newtonsoft.Json's JToken types work—resulting in the ArgumentException you encountered.
Here are three reliable solutions to resolve this:
1. Switch to BsonDocument (Recommended)
MongoDB's native BsonDocument is purpose-built to map directly to BSON structures, eliminating serialization conflicts entirely. This is the cleanest approach if you don't strictly need JObject.
Update Your Model
Modify the RoofDesign record to use BsonDocument? instead of JObject?:
using MongoDB.Bson; public record RoofDesign { public int CountOfPanels { get; init; } public RoofDesignImages? Images { get; init; } public BsonDocument? EditorData { get; init; } }
Handle Frontend Input
When receiving JSON from the frontend, parse it directly into a BsonDocument:
// Example: Convert frontend JSON string to BsonDocument var editorDataJson = "{\"additionalProp1\": [null], \"additionalProp2\": [null], \"additionalProp3\": [null]}"; var editorData = BsonDocument.Parse(editorDataJson);
The MongoDB driver will serialize BsonDocument into clean, native BSON without extra type fields, and deserialization will work seamlessly.
2. Use MongoDB's Newtonsoft.Json Serializer Package
If you need to keep using JObject, configure the MongoDB driver to use Newtonsoft.Json for serialization instead of its default serializer. This ensures proper handling of JToken types.
Install the Package
Add the MongoDB.Driver.NewtonsoftJson NuGet package to your project.
Configure the Mongo Client
Update your MongoDB client initialization to enable Newtonsoft.Json serialization:
using MongoDB.Driver; using MongoDB.Driver.NewtonsoftJson; var mongoSettings = MongoClientSettings.FromConnectionString("your-mongodb-connection-string"); // Enable Newtonsoft.Json serialization for proper JObject handling mongoSettings.UseNewtonsoftJson(); var mongoClient = new MongoClient(mongoSettings);
This setup tells the driver to use Newtonsoft.Json's serializer, which understands JObject and JArray natively—no more _t/_v fields, and deserialization will work as expected.
3. Implement a Custom JObject Serializer
If you can't use the Newtonsoft.Json package, create a custom BSON serializer to handle JObject directly.
Create the Custom Serializer
using MongoDB.Bson.Serialization; using MongoDB.Bson; using Newtonsoft.Json.Linq; public class JObjectSerializer : IBsonSerializer<JObject> { public Type ValueType => typeof(JObject); public JObject Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { // Convert BSON document to JObject var bsonDoc = BsonDocumentSerializer.Instance.Deserialize(context, args); return JObject.Parse(bsonDoc.ToJson()); } public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, JObject value) { // Convert JObject to BSON document var bsonDoc = BsonDocument.Parse(value.ToString()); BsonDocumentSerializer.Instance.Serialize(context, args, bsonDoc); } // Explicit interface implementations for non-generic IBsonSerializer object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { return Deserialize(context, args); } void IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { Serialize(context, args, (JObject)value); } }
Register the Serializer
Add the serializer to your MongoDB driver settings during initialization:
var mongoSettings = MongoClientSettings.FromConnectionString("your-connection-string"); var serializerRegistry = new SerializerRegistry( new List<IBsonSerializer> { new JObjectSerializer() } ); mongoSettings.SerializerRegistry = serializerRegistry; var mongoClient = new MongoClient(mongoSettings);
This custom serializer converts between JObject and BsonDocument during serialization/deserialization, bypassing the driver's default type handling.
内容的提问来源于stack exchange,提问作者Brian Kessler

