asp.net core 3.1中对Mongodb BsonDocument的序列化和反序列化支持

最近项目使用了Mongodb作为非结构化数据的存储,大量使用了BsonDocument做为传输对象,但是面临一个问题,直接把BsonDocument通过web api返回前端时候,并不能序列化为期望的json;同样把json传输到后台也不能自动把json组装成BsonDocument

为此实现了一个自定义的asp.net core 3.1的JsonConverter来处理BsonDocument的序列化和反序列化。
首先定义一个BsonDocument的转换对象,并且实现JsonConverter<T>

public class BsonDocumentJsonConverter : JsonConverter<BsonDocument>
{
    /// <summary>
    /// 反序列化支持
    /// </summary>
    /// <param name="reader"></param>
    /// <param name="typeToConvert"></param>
    /// <param name="options"></param>
    /// <returns></returns>
    public override BsonDocument Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using (var jsonDoc = JsonDocument.ParseValue(ref reader))
        {
            using (var stream = new MemoryStream())
            {
                using (Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
                {
                    jsonDoc.WriteTo(writer);
                    writer.Flush();
                    string json = Encoding.UTF8.GetString(stream.ToArray());
                    return BsonDocument.Parse(json);
                }
            }
        }
    }
    /// <summary>
    /// 序列化支持
    /// </summary>
    /// <param name="writer"></param>
    /// <param name="value"></param>
    /// <param name="options"></param>
    public override void Write(Utf8JsonWriter writer, BsonDocument value, JsonSerializerOptions options)
    {
        if (value == null)
        {
            writer.WriteStringValue(String.Empty);
        }
        else
        {
            WirteJson(writer, value);
        }
    }
    private void WirteJson(Utf8JsonWriter writer, BsonDocument bson)
    {
        writer.WriteStartObject();
        var elements = bson.Elements;
        foreach (var item in elements)
        {
            WirteProperty(writer, item.Value, item.Name);
        }
        writer.WriteEndObject();
    }
    private void WirteProperty(Utf8JsonWriter writer, BsonValue bsonValue, string propertyName=null)
    {
        BsonType bsonType = bsonValue.BsonType;
        switch (bsonType)
        {
            case BsonType.EndOfDocument:
                break;
            case BsonType.Int32:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteNumberValue(bsonValue.AsInt32);
                }
                else
                {
                    writer.WriteNumber(propertyName, bsonValue.AsInt32);
                }
                break;
            case BsonType.Int64:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteNumberValue(bsonValue.AsInt64);
                }
                else
                {
                    writer.WriteNumber(propertyName, bsonValue.AsInt64);
                }
                break;
            case BsonType.Double:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteNumberValue(bsonValue.AsDouble);
                }
                else
                {
                    writer.WriteNumber(propertyName, bsonValue.AsDouble);
                }
                break;
            case BsonType.String:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteStringValue(bsonValue.AsString);
                }
                else
                {
                    writer.WriteString(propertyName, bsonValue.AsString);
                }
                break;
            case BsonType.Document:
                if (string.IsNullOrEmpty(propertyName))
                {
                    WirteJson(writer, bsonValue.AsBsonDocument);
                }
                else
                {
                    writer.WritePropertyName(propertyName);
                    WirteJson(writer, bsonValue.AsBsonDocument);
                }
                break;
            case BsonType.Array:
                if (string.IsNullOrEmpty(propertyName))
                {
                    var bsonArr = bsonValue.AsBsonArray;
                    writer.WriteStartArray();
                    foreach (var abson in bsonArr)
                    {
                        WirteProperty(writer, abson);
                    }
                    writer.WriteEndArray();
                }
                else
                {
                    var bsonArr = bsonValue.AsBsonArray;
                    writer.WritePropertyName(propertyName);
                    writer.WriteStartArray();
                    foreach (var abson in bsonArr)
                    {
                        WirteProperty(writer, abson);
                    }
                    writer.WriteEndArray();
                }
                break;
            case BsonType.Boolean:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteBooleanValue(bsonValue.AsBoolean);
                }
                else
                {
                    writer.WriteBoolean(propertyName, bsonValue.AsBoolean);
                }
                break;
            case BsonType.DateTime:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteStringValue(bsonValue.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:sszzz"));
                }
                else
                {
                    writer.WriteString(propertyName, bsonValue.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:sszzz"));
                }
                break;
            case BsonType.Null:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteNullValue();
                }
                else
                {
                    writer.WriteNull(propertyName);
                }
                break;
            case BsonType.ObjectId:
                if (string.IsNullOrEmpty(propertyName))
                {
                    writer.WriteStringValue(bsonValue.AsObjectId.ToString());
                }
                else
                {
                    writer.WriteString(propertyName, bsonValue.AsObjectId.ToString());
                }
                break;
            case BsonType.RegularExpression:
                break;
            case BsonType.JavaScript:
                break;
            case BsonType.Symbol:
                break;
            case BsonType.JavaScriptWithScope:
                break;
            case BsonType.Decimal128:
                break;
            case BsonType.MinKey:
                break;
            case BsonType.MaxKey:
                break;
            case BsonType.Timestamp:
                break;
            case BsonType.Binary:
                break;
            case BsonType.Undefined:
                break;
            default:
                break;
        }
    }
}

最后在Startup.cs文件中注册该转换器就好了

public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddControllersWithViews().AddJsonOptions(option => {
        //....
        option.JsonSerializerOptions.Converters.Add(new BsonDocumentJsonConverter());
    });
}
posted @   在路上—书生  阅读(986)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示