Getting Started with MongoDB and .NET Core 1.1 Web API

Coming from the Microsoft Stack, many .NET developers may overlook NoSQL databases. With amazing  tools like Entity Framework, SQL Express, SQL Object Explorer built right into Visual Studio, why would you want to use something else? There are many reasons for picking a NoSQL database over a SQL database, you can read about some of them here.


In this post we'll look at building a .NET Core 1.1 WebApi project connected to a MongoDB database. Web API's are some of the most common use cases for NoSQL databases.

Prerequisites

You have a little bit of ASP.NET MVC experience
You have Visual Studio 2018 installed
You have .NET Core 1.1 SDK installed

MongoDB

First we'll setup MongoDB on our machine.

Download

Grab the Community edition from their website.

Installation & Setup

Run the installer which will install MongoDB to the following directory:
c:\ Program Files\MongoDB

Navigate to C:\Program Files\MongoDB\Server\3.4\bin and create a config file named mongodb-config.cfg which tells MongoDB where to store data and logs. Here's what to write in it:

systemLog:
destination: file
path: "C:\\db\\mongodb\\log\\mongo.log"
logAppend: true
storage:
dbPath: "C:\\db\\mongodb\\data"
security:
authorization: disabled

Open up a command prompt and navigate to the same directory and run mongod.exe --config mongodb-config.cfg. Note: You can set a PATH variable so you can run mongoDB from anywhere.

Robomongo

In the bin directory you may have noticed 2 executables, mongod and mongo. mongod is the server daeemon and mongo is a client used to connect to the server. I prefer using Robomongo as the client. It provides a nice GUI to explore the database. Download it here.

Once it's installed, startup Robomongo and setup your connection as shown below:

Explore

Congratulations! You have a running database and a client connected to it. Take some time to play around here and add some data to get a feel for how it works.

.NET WebApi Application

Now we will create the web api.

Create Project

Open up VS2017 and go to File > New > Project and set it up as outlined below:

Hit OK. On the next screen select the Web API Template as shown before. Verify you're using .NET Core 1.1 as shown below:

The template inclues a simple controller to test things out with. Run the app and you should see something like this in your browser:

Connect to MongoDB

Install the MongoDB Driver for .NET. Open up Nuget Package Manager and search for "MongoDB.Driver" as shown below:

Select our project and click Install. At the time of writing, their latest version is 2.4.3.

Note: You may see a package called mongocsharpdriver. This is their legacy driver and they recommend you use the new package.

After agreeing to the terms and installing all the dependencies, we're ready to do some coding.

Model

Let's begin by creating our model. Create a Models folder in your project and inside add the following class:

using MongoDB.Bson.Serialization.Attributes;

namespace MongoWebApiDemo.Models
{
    public class Book
    {
        [BsonId]
        public int BookId { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public double Price { get; set; }
    }
}

Note: The BsonId element is necessary on one of your properties so that MongoDB has a unique identifier.

DBContext

With the model created, let's build our DBContext. It looks like this:

using MongoDB.Driver;
using MongoWebApiDemo.Models;
using System.Collections.Generic;

namespace MongoWebApiDemo.DAL
{
    public class MongoDBContext
    {
        private readonly IMongoDatabase _database = null;
        public MongoDBContext()
        {
            var client = new MongoClient("mongodb://localhost:27017");
            if (client != null)
                _database = client.GetDatabase("BookDemoDb");
        }

        public IMongoCollection Books
        {
            get
            {
                return _database.GetCollection("Books");
            }
        }
    }
}

As you can see, we've hard coded our connection string. This should come from a config file but to keep this short we will leave it as is.

CRUD

The Repository pattern is effective when communicating with the database, but to keep this tutorial simple, we will add simple CRUD operations directly into the MongoDBContext class. After adding these calls, it will look like this:

using MongoDB.Driver;
using MongoWebApiDemo.Models;
using System.Collections.Generic;

namespace MongoWebApiDemo.DAL
{
    public class MongoDBContext
    {
        private readonly IMongoDatabase _database = null;
        public MongoDBContext()
        {
            var client = new MongoClient("mongodb://localhost:27017");
            if (client != null)
                _database = client.GetDatabase("BookDemoDb");
        }

        public IMongoCollection Books
        {
            get
            {
                return _database.GetCollection("Books");
            }
        }


        public IEnumerable GetBooks()
        {
            return this.Books.Find(b => true).ToList();
        }

        public Book GetBook(int id)
        {
            var filter = Builders.Filter.Eq("BookId", id);
            return this.Books.Find(filter).FirstOrDefault();
        }

        public Book InsertBook(Book book)
        {
            this.Books.InsertOne(book);
            return book;
        }

        public void ReplaceBook(Book book)
        {
            var filter = Builders.Filter.Eq("BookId", book.BookId);
            this.Books.ReplaceOne(filter, book);
        }

        public void RemoveBook(int id)
        {
            var filter = Builders.Filter.Eq("BookId", id);
            this.Books.DeleteOne(filter);
        }
    }
}

Seed Data

With the context class ready, let's add some seed data. Create a new file in the DAL folder named Initializer.cs

using MongoDB.Driver;
using MongoWebApiDemo.Models;
using System.Collections.Generic;

namespace MongoWebApiDemo.DAL
{
    public class DbInitializer
    {

        public static void SeedDatabase(MongoDBContext context)
        {
            //db has books already
            if (context.Books.Find(b => true).Count() != 0) return;


            var books = new List()
            {
                new Book{BookId = 0, Author = "J.K. Rowling", Title = "Harry Potter", Price = 18.99},
                new Book{BookId = 1, Author = "J.R.R. Tolkien", Title = "Lord of the Rings", Price = 22.99},
                new Book{BookId = 2, Author = "Moby Dick", Title = "Herman Mellvile", Price = 11.99},
                new Book{BookId = 3, Author = "Hamlet", Title = "William Shakespear", Price = 14.99},
            };

            context.Books.InsertMany(books);
        }
    }
}

In Startup.cs, call the SeedDatabase function.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
	loggerFactory.AddConsole(Configuration.GetSection("Logging"));
	loggerFactory.AddDebug();

	app.UseMvc();

	MongoDBContext context = new MongoDBContext();
	DbInitializer.SeedDatabase(context);
}

Run the application and verify the data is there with RoboMongo.

Controller

Time to hook everything up to the controller. Create a new named BooksController.cs.

using Microsoft.AspNetCore.Mvc;
using MongoWebApiDemo.DAL;
using MongoWebApiDemo.Models;
using System.Collections.Generic;

namespace MongoWebApiDemo.Controllers
{
    [Route("api/[controller]")]
    public class BooksController : Controller
    {
        MongoDBContext _context;
        public BooksController()
        {
            _context = new MongoDBContext();
        }

        // GET api/books
        [HttpGet]
        public IEnumerable Get()
        {
            return _context.GetBooks();

        }

        // GET api/books/5
        [HttpGet("{id}")]
        public Book Get(int id)
        {
            return _context.GetBook(id);
        }

        // POST api/books
        [HttpPost]
        public void Post([FromBody]Book book)
        {
            _context.InsertBook(book);
        }

        // PUT api/books/5
        [HttpPut]
        public void Put([FromBody]Book book)
        {
            _context.ReplaceBook(book);
        }

        // DELETE api/books/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
            _context.RemoveBook(id);
        }
    }
}

Run

Before launching the application, let's update the launchUrl since we changed the name of the controller. In LaunchSettings.json replace the launchUrl values from api/values to api/books.

Launch the application and our simple WebApi using MongoDB is ready to go! Try out the different calls we created. I like to use PostMan to quickly review API calls.

Thanks for Reading

I hope this made it easy for .NET developers that haven't taken the plunge into NoSql databases to get their hands dirty. Leave any questions or comments below!