How to MongoDB in C# – Part 1

Every new project holds new surprises and adventures, but imagine my surprise when realizing I am the victim who is going to work with MongoDB. As a C# developer who is accustomed to SQL server, I was like:

So.. when the news were digested, I did the next best thing – googled “MongoDB” ( also binged 😉 )

A few hours later, I was frustrated with my findings. There were a lot of examples on how to work my way up the old legacy driver, but very few ones with the new C# driver API.

And so I decided to write this blog-post series on “How to MongoDB in C#”, to save you the frustration part of my journey.

This post will briefly talk about how to setup MongoDB etc. (there are more then plenty tutorials concerning that topic). But, in the ones to follow, I will be focusing on the different ways MongoDB’s CRUD API has to offer, both standard and advanced (called Aggregation-FW). In order to reach the interesting stuff, we will have to setup our development environment.

This JSON structure will represent our “Developer” object inside the DB (well actually, MongoDB stores objects as BSON objects which are a binary JSON, but that is a topic for a different blog post).

In MongoDB, everything is considered to be a document (or to be precise, a BsonDocument – in the C# API. Later on, I will explain the correlation between our strongly typed Developer class and MongoDB’s BsonDocument).

So here is our corresponding C# class representation of the JSON object:

Throughout this post-series, we will be using a variety of OzCode’s finest 🙂

We are going to use MongoDB’s CRUD operation to work with a lot (and I mean, A LOT) of data, so we better equip our selves with the proper debugging tools.

I will be demonstrating how to search through a retrieved collection of objects using the Search feature , how to filter them and display only those which answer specific criteria using Collection-Filtering and even export the huge amount of data using Export (see in action starting from the 26:30 minute)

In the screenshot above I’m using OzCode’s awesome Reveal feature to better visualize the debug experience, otherwise I would need to wrap my POCO objects with a DebuggerDisplayAttribute or even worse, building a debugger proxy using DebuggerTypeProxyAttribute. (Developer class debug-display can be configured by selecting the relevant asterisks)

About that MongoDB’s object mapping

There is a bunch of new stuff you are probably wondering about, let’s go over it.

As you’ve probably noticed, I don’t have to match my C# class properties to the JSON object, MongoDB offers two different ways to achieve that during its store and retrieve operations:

“Automatic” – which is attribute-based. there is also a way of defining system-wide general conventions using ConventionPack

Here as you can see, our Developer class is missing its ID property (the last property in the tree is missing).

I’m using MongoDB ‘s client (ships with the installation), to retrieve the inserted Developer object. Although we didn’t add an ID property, you can clearly see MongoDB has added it for us:

**Be aware – when retrieving this object back into your C# application, MongoDB will throw an exception telling you an ID property is missing. If You decide to choose this strategy for your application, you must mark your class with BsonIgnoreExtraElements

If you do decide to decorate your class with an ID property, you are not obligated to use MongoDB ‘s ObjectId struct. Actually, the ID can be of different types, such as string, int or even GUID. The main thing to remember is that MongoDB assigns an Index of type Unique to it’s “_id” field. So make sure you add an entry with a unique ID value, because same as in remark #3 it will use the default value for your ID type (Except GUID type – MongoDB will auto generate values for it), and will throw an exception when trying to add an entry with the same default ID value.

You can use an IdGenerator of type IIdGenerator, as a BsonIdAttribute parameter. There are few build-in IdGenerator which you can leverage from such as the StringObjectIdGenerator in case you don’t want to use the ObjectId struct. Passing this type to your BsonIdAttribute, will store ObjectId’s string representation onto your ID property.

The way it works, for each document MongoDB tries to insert, it will pass the ID value into IsEmpty method, returning true will pass the document to GenerateId method, which accepts a container (the Collection responsible for your document’s CRUD operations, amount other stuff) and the document itself.

Using MongoDB’s automatic conventions

One last thing – I have mentioned earlier we can generalize our application using ConventionPack.

Consider the following example: your team decides all property names will be stored as lower cased and an underscore will separate between each capital letter inside MongoDB (CompanyName becomes company_name). This type of decision will require you to go over each document and its properties, and apply the name convention. What if you refactor your class? what if a new convention will be set by your team?

Luckily (!!) MongoDB offers a convention based API.

You can create a ConventionPack instance, which is basically a collection of IConvention types (MongoDB offers a wide range of predefined conventions for you which can be found here). You can then add as many conventions as you’d like, and register the ConventionPack within the “ConventionRegistry.Register” static method.

The method accepts 3 parameters:

Name for your convention pack

The ConventionPack to be used

A Func<Type,bool> filter, to which types this convention doesn’t apply to (simply pass a “t => true” to apply for all types)

I decided to implement the 2 conventions I had described earlier based on IMemberMapConvetion (derives from IConvention), and apply them only to the Developer class. Now our Developer class looks a bit cleaner:

Oh yeah, there is also the Manual way of things

This is addressed to all those coders, who loveeee to type :). As you might imagine, anything which can be done in the automated (attribute-based) way can be done in the manual way. I Won’t elaborate much on this part, because this manual has a pretty decent tutorial on how to work with the manual way (and the automated way, in a much MORE detailed-oriented way).

So…. we covered so far the top-most basics of:

The relationship between JSON object and it’s twin C# brother, the Document.

How to setup and customize your class using attributes

ID property highlights – from MongoDB ‘s perspective

What’s next

But there’s still a lot to cover during our dive into MongoDB , in the next post and future ones I will cover the following:

How to setup your DB connection

How to instantiate the MongoClient, MongoDatabase and MongoCollection classes