Deano
Deano

Reputation: 2895

MongoDB - How to ignore deserialization errors

I am using the MongoDB CSharp driver to retrieve a collection of data. Unfortunately some of this data isn't very "clean" as some fields are strings and integers at the same time. As expected, the deserialization process is throwing an exception every time it hits data that doesn't match the correct type.

I have searched the net far and wide, as well as StackOverflow and have had no luck. Is there a way to simply handle/ignore exceptions when deserializing and move onto the next record?

My code looks something similar to this:

        MongoClient client = new MongoClient(MongoConnectionString);
        MongoServer server = client.GetServer();
        MongoDatabase database = server.GetDatabase(DatabaseName);

        MongoCollection<BookingLines> bookingLines = database.GetCollection<BookingLines>("bookinglines");

        var query = from e in bookingLines.AsQueryable() where e.Status != "void" select e;

The code normally throws an error on the last line above. I have also tried adding the [BsonIgnore] attribute to certain fields.

Any ideas or suggestions would be very helpful.

Upvotes: 2

Views: 4614

Answers (3)

Slack Groverglow
Slack Groverglow

Reputation: 856

You can try using the BsonClassMapSerializer<T> as a custom deserializer:

public class CustomIgnoreErrorsSerializer<T> : BsonClassMapSerializer<T>
{
    public CustomIgnoreErrorsSerializer(BsonClassMap classMap) : base(classMap) { }

    public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        try
        {
            return base.Deserialize(context, args);
        }
        catch (Exception ex)
        {
            while (context.Reader.State != BsonReaderState.EndOfDocument)
            {
                if (context.Reader.State == BsonReaderState.Name)
                    context.Reader.SkipName();
                if (context.Reader.State == BsonReaderState.Value)
                    context.Reader.SkipValue();
                if (context.Reader.State == BsonReaderState.Type)
                    context.Reader.ReadBsonType();
            }
            context.Reader.ReadEndDocument();
            return default(T);
        }
    }
}

There's some extra work you need to do including skipping the BsonReader to the end of the current document.

Then to register this deserializer, because its a BsonClassMapSerializer type you need to pass the class map for that type and you have to do this for every collection type you want this to be applied to.

var cm = BsonClassMap.LookupClassMap(typeof(MyType));
BsonSerializer.RegisterSerializer(new CustomIgnoreErrorsSerializer<MyType>(cm));

Upvotes: 0

WiredPrairie
WiredPrairie

Reputation: 59773

You can't use a strongly typed object without a lot of extra effort if there is a lot of variance in structure and field dats types. I'd suggest you consider using BsonDocument which will allow any document to be serialized and deserialized, as shown in the various tutorials here.

You could use it as an intermediary format if needed as well, and run through some sanitizing code to convert it to a strongly typed C# class.

If you want to use a strongly typed class, you also can create a custom serializer for various fields as shown here, or take control of the full serialization process as described here.

Upvotes: 5

testydonkey
testydonkey

Reputation: 149

Are you able to clean the data before insertion? Generally, like SQL, you don't want to put crap into your database.

Another way (if you don't need the dodgy fields) would be to simply not include them in the BookingLines object?

Upvotes: 1

Related Questions