Decimal serialization for decimal.MaxValue and decimal.MinValue

XMLWordPrintableJSON

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

       

       

       

            Assignee:
            Adelin Mbida Owona
            Reporter:
            Lukas Vosyka
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: