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());
});
}