在ASP.NET Core 6中如何高效将JsonElement转换为BsonDocument?
JsonElement转BsonDocument的高效实现方案
直接序列化字符串再解析的方式确实会产生额外性能开销,下面提供几种更高效的实现思路:
方案一:直接通过BsonWriter构建BsonDocument
这种方式跳过中间字符串转换,直接将JsonElement的节点映射为Bson类型,性能最优。
using MongoDB.Bson; using MongoDB.Bson.IO; using System.Text.Json; public static BsonDocument ConvertJsonElementToBson(JsonElement element) { using var stream = new MemoryStream(); using var bsonWriter = new BsonBinaryWriter(stream); var writer = new BsonWriter(bsonWriter); WriteElementToBson(writer, element); stream.Position = 0; return BsonDocument.ReadFrom(bsonWriter); } private static void WriteElementToBson(BsonWriter writer, JsonElement element) { switch (element.ValueKind) { case JsonValueKind.Object: writer.WriteStartDocument(); foreach (var prop in element.EnumerateObject()) { writer.WriteName(prop.Name); WriteElementToBson(writer, prop.Value); } writer.WriteEndDocument(); break; case JsonValueKind.Array: writer.WriteStartArray(); foreach (var item in element.EnumerateArray()) { WriteElementToBson(writer, item); } writer.WriteEndArray(); break; case JsonValueKind.String: writer.WriteString(element.GetString()); break; case JsonValueKind.Number: if (element.TryGetInt32(out var intVal)) writer.WriteInt32(intVal); else if (element.TryGetInt64(out var longVal)) writer.WriteInt64(longVal); else if (element.TryGetDouble(out var doubleVal)) writer.WriteDouble(doubleVal); else if (element.TryGetDecimal(out var decVal)) writer.WriteDecimal128(new Decimal128(decVal)); break; case JsonValueKind.True: case JsonValueKind.False: writer.WriteBoolean(element.GetBoolean()); break; case JsonValueKind.Null: writer.WriteNull(); break; case JsonValueKind.Undefined: writer.WriteUndefined(); break; default: throw new NotSupportedException($"不支持的JsonValueKind类型:{element.ValueKind}"); } }
方案二:反序列化为强类型对象再转换
如果JsonElement对应的JSON结构是固定的,可以先反序列化为具体的DTO类,再通过BsonDocument.Create生成BsonDocument,代码更简洁:
// 假设已有对应的DTO类MyModel var model = myJsonElement.Deserialize<MyModel>(); var bsonDoc = BsonDocument.Create(model);
如果是动态结构,可自定义转换器将JsonElement转为Dictionary<string, object>后再转换:
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, Converters = { new JsonElementToObjectConverter() } }; var dynamicObj = myJsonElement.Deserialize<Dictionary<string, object>>(options); var bsonDoc = BsonDocument.Create(dynamicObj); // 自定义转换器:将JsonElement转为对应.NET类型 public class JsonElementToObjectConverter : JsonConverter<object> { public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); return ConvertElement(doc.RootElement); } private object ConvertElement(JsonElement element) { switch (element.ValueKind) { case JsonValueKind.Object: return element.EnumerateObject() .ToDictionary(kv => kv.Name, kv => ConvertElement(kv.Value)); case JsonValueKind.Array: return element.EnumerateArray().Select(ConvertElement).ToList(); case JsonValueKind.String: return element.GetString(); case JsonValueKind.Number: if (element.TryGetInt64(out var longVal)) return longVal; if (element.TryGetDouble(out var doubleVal)) return doubleVal; return element.GetDecimal(); case JsonValueKind.True: case JsonValueKind.False: return element.GetBoolean(); case JsonValueKind.Null: return null; default: throw new NotSupportedException(); } } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { throw new NotImplementedException(); } }
方案三:借助Newtonsoft.Json中转(适合快速实现)
如果项目已引用Newtonsoft.Json,可先将JsonElement转为JObject再生成BsonDocument,实现简单:
using Newtonsoft.Json.Linq; var jObj = JObject.Parse(myJsonElement.GetRawText()); var bsonDoc = BsonDocument.Create(jObj);
这种方式虽有中间转换,但代码量少,适合性能要求不极端的场景。
内容的提问来源于stack exchange,提问作者Roman Koliada
相关产品推荐
相关产品推荐

