.NET 6中使用System.Text.Json序列化BsonDocument时出现类型转换错误
问题描述
我定义了如下C#类:
public class Product { public string ProductName { get; set; } public int ProductCount { get; set; } public BsonDocument ProductMetadata { get; set; } }
其中BsonDocument来自MongoDB.Driver。我的API代码如下:
// GET: api/<ProductController> [HttpGet] public Product Get() { Product prod = new Product(); prod.ProductName = "Test"; prod.ProductCount = 20; var doc = new BsonDocument { { "metadata1", "val1" } }; prod.ProductMetadata = doc; return prod; }
调用该Get接口时出现以下错误:
An unhandled exception occurred while processing the request. InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonString' to type 'MongoDB.Bson.BsonBoolean'. System.Text.Json.Serialization.Metadata.JsonPropertyInfo<T>.GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer) System.Text.Json.Serialization.Converters.ObjectDefaultConverter<T>.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) System.Text.Json.Serialization.JsonConverter<T>.TryWrite(Utf8JsonWriter writer, ref T value, JsonSerializerOptions options, ref WriteStack state) System.Text.Json.Serialization.Metadata.JsonPropertyInfo<T>.GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer) System.Text.Json.Serialization.Converters.ObjectDefaultConverter<T>.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) ....
序列化器试图将metadata1转换为布尔类型,这是什么原因?
问题原因
ASP.NET Core默认使用System.Text.Json做序列化,但它没有内置BsonDocument的处理逻辑。BsonDocument的元素是BsonValue类型,System.Text.Json反射序列化时会遍历BsonValue的所有属性,包括AsBoolean这类强类型转换属性——当BsonValue实际是字符串类型(比如你的metadata1对应BsonString),访问AsBoolean就会触发类型转换异常,这就是错误的根源。
解决方法
方案1:全局配置自定义转换器
为BsonDocument编写System.Text.Json转换器,让序列化器正确识别各类型的BsonValue:
public class BsonDocumentJsonConverter : JsonConverter<BsonDocument> { public override BsonDocument Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 若需支持反序列化,可在此实现逻辑 throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, BsonDocument value, JsonSerializerOptions options) { writer.WriteStartObject(); foreach (var element in value) { writer.WritePropertyName(element.Key); WriteBsonValue(writer, element.Value); } writer.WriteEndObject(); } private void WriteBsonValue(Utf8JsonWriter writer, BsonValue value) { switch (value.BsonType) { case BsonType.String: writer.WriteStringValue(value.AsString); break; case BsonType.Int32: writer.WriteNumberValue(value.AsInt32); break; case BsonType.Boolean: writer.WriteBooleanValue(value.AsBoolean); break; case BsonType.Double: writer.WriteNumberValue(value.AsDouble); break; // 根据业务需求添加其他Bson类型的处理 default: writer.WriteStringValue(value.ToString()); break; } } }
然后在Program.cs中注册转换器:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new BsonDocumentJsonConverter()); });
方案2:局部转换为通用类型
在返回前把BsonDocument转换成System.Text.Json能正常处理的类型,比如Dictionary<string, object>或匿名对象:
[HttpGet] public object Get() { Product prod = new Product(); prod.ProductName = "Test"; prod.ProductCount = 20; var doc = new BsonDocument { { "metadata1", "val1" } }; // 转换为Dictionary var metadataDict = doc.ToDictionary(kv => kv.Key, kv => kv.Value.ToObject<object>()); return new { prod.ProductName, prod.ProductCount, ProductMetadata = metadataDict }; }
这种方式无需修改全局配置,适合单个接口的局部处理。
方案3:切换到Newtonsoft.Json序列化
ASP.NET Core也支持使用Newtonsoft.Json(Json.NET),它对BsonDocument的兼容性更好:
- 安装
Microsoft.AspNetCore.Mvc.NewtonsoftJson包 - 在
Program.cs中配置:
builder.Services.AddControllers() .AddNewtonsoftJson();
之后BsonDocument会被自动序列化为对应的JSON结构,无需额外处理。
内容的提问来源于stack exchange,提问作者simoha
相关产品推荐
相关产品推荐

