1

I'm upgrading an existing project from the 1.10.0 Mongo Driver to 2.2.4 and encountered some unexpected behavior in a class that inherits from MongoDB.Bson.BsonDocument. The original developers extended BsonDocument with a class called BsonDocumentWithNulls whose entire purpose is to convert null to BsonNull.Value.

In unit tests Assert.AreEqual(new BsonDocument("foo", "bar"), new BsonDocumentWithNulls("foo", "baz")); fails as it should but the error message doesn't recognize the values in the BsonDocumentWithNulls object. Specifically the error message is Assert.AreEqual failed. Expected:<{ "foo" : "bar" }>. Actual:<[{ }]>. I know this has something to do with ToString but I don't know how to fix it.

This is the implementation of BsonDocumentWithNulls which works with 1.10.0 of the Mongo driver, but not version 2.2.4.

public sealed class BsonDocumentWithNulls : BsonDocument
    {
        public BsonDocumentWithNulls()
        { }

        public BsonDocumentWithNulls(string key, BsonValue value)
        {
            if (value == null)
                Add(key, BsonNull.Value);
            else
                Add(key, value);
        }

        public BsonDocumentWithNulls(IDictionary<string, object> dictionary)
        {
            foreach (var keyValue in dictionary)
            {
                if (keyValue.Value == null)
                    Add(keyValue.Key, BsonNull.Value);
                else
                    Add(keyValue.Key, BsonValue.Create(keyValue.Value));
            }
        }
    }

To add to the confusion I can make the following Assertions in Unit Tests and everything works, which tells me the values are actually being stored in memory.

BsonDocument expected = new BsonDocument("foo", "bar");
BsonDocumentWithNulls actual = new BsonDocumentWithNulls("foo", "bar");

Assert.AreEqual(expected["foo"], actual["foo"]); 
Assert.AreEqual(expected.GetElement("foo"), actual.GetElement("foo"));
Assert.AreEqual(expected, actual);
//And just for sanity
Assert.AreEqual("bar", actual["foo"]);

To try and fix the problem I've tried overriding ToString with various implementations.

public override string ToString()
{
    return base.ToString();
}

public override string ToString()
{
    BsonDocument doc = this.AsBsonDocument;
    return doc.ToString();
}

And one of my more naive/creative attempts, but I'll let you be the judge on if its creative or naive.

public override string ToString()
{
    string retVal = string.Empty;

    foreach(var val in this.Elements)
    {
        retVal += string.Format("{2}, \"{0}\" : \"{1}\" {3}", val.Name, val.Value, "{", "}");
    }
    return retVal;
}
HopAlongPolly
  • 1,347
  • 1
  • 20
  • 48

1 Answers1

0

This is more of a hack than an answer but it got me through the issue I was having and since the BsonDocumentWithNulls was only implementing constuctors it was a fairly easy work around.

public sealed class BsonDocumentWithNulls : BsonDocument
    {
        public BsonDocument doc { get; set; }

        public BsonDocumentWithNulls()
        {
            doc = new BsonDocument();
        }

        public BsonDocumentWithNulls(string key, BsonValue value)
        {
            doc = new BsonDocument();
            if (value == null)
                doc.Add(key, BsonNull.Value);
            else
                doc.Add(key, value);
        }

        public BsonDocumentWithNulls(IDictionary<string, object> dictionary)
        {
            doc = new BsonDocument();
            foreach (var keyValue in dictionary)
            {
                if (keyValue.Value == null)
                    doc.Add(keyValue.Key, BsonNull.Value);
                else
                    doc.Add(keyValue.Key, BsonValue.Create(keyValue.Value));
            }
        }

        public override string ToString()
        {
            return doc.ToString();
        }

        public BsonDocument ToBsonDocument()
        {
            return doc;
        }
    }

The most common usage of this class was something like

var doc = new BsonDocumentWithNulls {
    {"key1" : 1 },
    {"key2" : "val2" }
};

it was really easy to just tack on .ToBsonDocument()

var doc = new BsonDocumentWithNulls {
    {"key1" : 1 },
    {"key2" : "val2" }
}.ToBsonDocument();
HopAlongPolly
  • 1,347
  • 1
  • 20
  • 48