-
Type: Bug
-
Resolution: Unresolved
-
Priority: Unknown
-
None
-
Affects Version/s: None
-
Component/s: Serialization
-
None
Summary
I try to serialize/deserialize BsonDocument. We are using explicit field level encryption and MongoDbDriver 2.17.1
We decrypt the value and parse it to BsonDocument. When we want to return serialized model from API that contains a field of type BsonDocument, we receive this error:
System.InvalidCastException: Specified cast is not valid. at MongoDB.Bson.BsonValue.System.IConvertible.ToType(Type conversionType, IFormatProvider provider) at Newtonsoft.Json.JsonWriter.ResolveConvertibleValue(IConvertible convertible, PrimitiveTypeCode& typeCode, Object& value) at Newtonsoft.Json.JsonWriter.WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, Object value) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType) at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType) at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
It happens for the field BsonNull which is regular type of Bson, but it doesnt exist in this method:
object IConvertible.ToType(Type conversionType, IFormatProvider provider) { if (conversionType == typeof(object)) { return this; } switch (BsonType) { case BsonType.Boolean: return Convert.ChangeType(this.AsBoolean, conversionType, provider); case BsonType.DateTime: return Convert.ChangeType(this.ToUniversalTime(), conversionType, provider); case BsonType.Decimal128: return Convert.ChangeType(this.AsDecimal128, conversionType, provider); case BsonType.Double: return Convert.ChangeType(this.AsDouble, conversionType, provider); case BsonType.Int32: return Convert.ChangeType(this.AsInt32, conversionType, provider); case BsonType.Int64: return Convert.ChangeType(this.AsInt64, conversionType, provider); case BsonType.ObjectId: return Convert.ChangeType(this.AsObjectId, conversionType, provider); case BsonType.String: return Convert.ChangeType(this.AsString, conversionType, provider); default: throw new InvalidCastException(); } }
The version of MongoDb.Bson is 2.17.0
We are using MongoDB Community edition version 6.0.0
How to Reproduce
Decrypt the value from the db: (CompanyName is BsonDocument)
decodedWorkflow.CompanyName = (await clientEncryption.DecryptAsync(workflow.CompanyName)).AsBsonDocument;
When we check the type of decodedWorkflow.CompanyName, it is RawBsonDocument. The only way to get it to work as BsonDocument is either to convert it to string or to use:
BsonDocument.Parse(JsonConvert.SerializeObject(BsonTypeMapper.MapToDotNetValue(await clientEncryption.DecryptAsync(workflow.CustomFields))));
When the type of this field is BsonDocument (instead RawBsonDocument), then the serialization works.
I am not sure, if the type should be RawBsonDocument, but then this method: IConvertible.ToType should support Nullable type?
Additional Background