-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Unknown
-
None
-
Affects Version/s: 3.5.0, 3.5.1
-
Component/s: Serialization
-
None
-
None
-
Dotnet Drivers
-
None
-
None
-
None
-
None
-
None
-
None
Hi,
I stumbled across this "feature" of the MongoDb driver and not sure what intention is behind this, as I believe, from a .NET perspective it is not expected.
I am wondering about the serialization behavior of decimal.MaxValue (and decimal.MinValue) using the default DecimalSerializer. When configured as representation Bson.Decimal128 it decimal.MaxValue gets serialized as { "$numberDecimal" : "9.999999999999999999999999999999999E+6144" }
When using classes for serialization and deserialization, it works fine and the decimal contains the correct value. However, when trying to deserialize to a BsonDocument and the use `AsDecimal` on the BsonValue it fails.
Having a closer look into the source it seems that this very "case" is handled by the RepresentationConverter during (de)serialization, however Decimal128 doesn't do that, the qustion is why.
One could argue to move this block to Decimal128 type at the beginning of
public static decimal ToDecimal(Decimal128 d)
if (d == Decimal128.MaxValue) { return decimal.MaxValue; } else if (d == Decimal128.MinValue) { return decimal.MinValue; }
I have created test cases for reproducability.
// code placeholder using EphemeralMongo; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; using Xunit; namespace DecimalSerialization; public class DecimalTests : IDisposable { private readonly IMongoRunner _runner = MongoRunner.Run(new MongoRunnerOptions()); private class TestClass { [BsonId] ObjectId Id { get; set; } public decimal SomeDecimal { get; set; } } [Fact] public async Task DecimalMaxShouldSerializeBackAndForthViaClass() { var collection = Database.GetCollection<TestClass>("test"); await collection.InsertOneAsync(new TestClass { SomeDecimal = decimal.MaxValue }, TestContext.Current.CancellationToken); var result = await collection.Find(Builders<TestClass>.Filter.Empty).FirstAsync(TestContext.Current.CancellationToken); Assert.Equal(decimal.MaxValue, result.SomeDecimal); } [Fact] public async Task DecimalMaxShouldSerializeBackAndForthViaBsonDocument() { var collection = Database.GetCollection<TestClass>("test"); await collection.InsertOneAsync(new TestClass { SomeDecimal = decimal.MaxValue }, TestContext.Current.CancellationToken); var bsonCollection = Database.GetCollection<BsonDocument>("test"); var result = await bsonCollection.Find(Builders<BsonDocument>.Filter.Empty).FirstAsync(TestContext.Current.CancellationToken); Assert.Contains("SomeDecimal", result.Names); Assert.Equal(decimal.MaxValue, result["SomeDecimal"].AsDecimal); } private IMongoDatabase Database => Client.GetDatabase("DecimalSerialization"); private IMongoClient Client => new MongoClient(MongoClientSettings.FromConnectionString(_runner.ConnectionString)); public void Dispose() { _runner.Dispose(); } }