Using MongoDB .NET Driver with .NET Core WebAPI

What’s about

Problem / solution format brings an easier understanding on how to build things, giving an immediate feedback. Starting from this idea, the blog post I will present step by step how to build

a web application to store your ideas in an easy way, adding text notes, either from desktop or mobile, with few characteristics: run fast, save on the fly whatever you write, and be reasonably reliable and secure.

This article will implement just the backend, WebApi and the database access, in the most simple way.

A couple of updates done to the original article

Following Peter’s comment, I have simplified the documents returned, see HttpGet requests

Following Luciano’s comment, I have extend the update function, making update of the full MongoDB documents at once, not just to some of the properties. There is a new section below, describing this change

Trying to read from Angular 2, find the article here, I have ran into CORS problems. An error message was displayed “No ‘Access-Control-Allow-Origin’ header is present on the requested resource”. I have added a new section to describe the solution.

Technology stack

The ASP.NET Core Web API has the big advantage that it can be used as HTTP service and it can be subscribed by any client application, ranging from desktop to mobiles, and also be installed on Windows, macOS or Linux.

MongoDB is a popular NoSQL database that makes a great backend for Web APIs. These lend themselves more to document store type, rather than to relational databases. This blog will present how to build a .NET Core Web API connected asynchronously to MongoDB, with full support for HTTP GET, PUT, POST, and DELETE.

Creating the ASP.NET WebApi project

Configuration

There are multiple file formats, supported out of the box for the configuration (JSON, XML, or INI). By default, the WebApi project template comes with JSON format enabled. Inside the setting file, order matters, and include complex structures. Here is an example with a 2 level settings structure for database connection.AppSettings.json – update the file:

Dependency injection and Options model

Constructor injection is one of the most common approach to implementing Dependency Injection (DI), though not the only one. ASP.NET Core uses constructor injection in its solution, so we will also use it. ASP.NET Core project has a Startup.cs file, which configures the environment in which our application will run. The Startup.cs file also places services into ASP.NET Core’s Services layer, which is what enables dependency injection.

To map the custom database connection settings, we will add a new Settings class.

Further in the project, settings will be access via IOptions interface:

IOptions<Settings>

MongoDB configuration

Once you have installed MongoDB, you would need to configure the access, as well as where the data is located.

To do this, create a file locally, named mongod.cfg. This will include setting path to the data folder for MongoDB server, as well as to the MongoDB log file, initially without any authentication. Please update these local paths, with your own settings:

Run in command prompt next line. This will start the MongoDB server, pointing to the configuration file already created (in case the server is installed in a custom folder, please update first the command)

Once the server is started (and you could see the details in the log file), run mongo.exe in command prompt. The next step is to add the administrator user to the database. Run mongodb with the full path (ex: “C:\Program Files\MongoDB\Server\3.2\bin\mongo.exe”).

From now on, we’ll connect to MongoDb using admin user. There is a good practice to not use the superuser role (in our case administrator) for normal operations, but in order to keep the things simple, we will continue to have just a single user.

MongoDB .NET Driver

To connect to MongoDB, add via Nuget the package named MongoDB.Driver. This is the new official driver for .NET, fully supporting the ASP.NET Core applications.

Model

The model class (POCO) associated with each entry in the notebook is included below:

Adding the repository

Using a repository interface, we will implement the functions needed to manage the Notes. These will also use Dependency Injection (DI) to be easily access from the application (e.g. controller section):

In order to access NoteRepository using DI model, we add a new line in ConfigureServices

services.AddTransient<INoteRepository, NoteRepository>();

where:

Transient: Created each time.

Scoped: Created only once per request.

Singleton: Created the first time they are requested. Each subsequent request uses the instance that was created the first time.

Adding the main controller

First we present the main controller. It provides all the CRUD interfaces, available to external applications.
The Get actions have NoCache directive, to ensure web clients make always requests to the server.

Adding the admin controller

This will be a controller dedicated to administrative tasks (we use to initialize the database with some dummy data). In real projects, we should very cautiously use such interface. For development only and quick testing purpose, this approach may be convenient.

To use it, we will just add the url in the browser. Running the code below, the full setup will be automatically created (e.g. new database, new collection, sample records). We can use either http://localhost:5000/api/system/init or http://localhost:53617/api/system/init(when using IIS). We could even extend the idea, adding more commands. However, as mentioned above, these kind of scenarios should be used just for development, and be never deployed to a production environment.

Running project on GitHub

Allowing Cross Domain Calls (CORS)

Being different applications, running on separate domains, all calls back to ASP.NET WebAPI site are effectively cross domain calls. With Angular 2, there is first a pre-flight request, before the actual request, (an OPTIONS request). Doing this pre-check, we verify first that cross domain calls are allowed (CORS).

I have enabled CORS by applying two changes:

First register CORS functionality in ConfigureServices() of Startup.cs:

In this way we handle a faulted task by asynchronously wait for it to complete, using await. This will rethrow the original stored exception.

Initially I have used void as return. Changing the return type, the exception raised in the async method will get safely saved in the returning Task instance. When we await the faulty method, the exception saved in the Task will get rethrown with its full stack trace preserved.

Related Posts:

38 comments
On Using MongoDB .NET Driver with .NET Core WebAPI

Hello Petru,
I have followed all the above steps but The only output i get on the browser is the empty braces ” [ ]” and I don’t find the database and collection in MongoDB. Any help would be greatly appreciated.
Thanks

Connecting with RoboMongo to your local MongoDb installation, do you see the database “NotesDb” and collection “Note” ? If not, return to the solution, and check if SystemController is used and it doesn’t raise any exception (using the url: http://localhost:53617/system/init).

I am trying to setup a similar structure but within a .NET Core web application instead of an API. I have everything setup in a similar way, but now I am trying to call the equivalent to your NotesController. I am unable to create INotesRepository to be sent into the constructor function, I am not familiar with how web API’s work therefore I don’t see how that is being sent into your NotesController function as well. Any information is much appreciated! Thanks, Al

To change the connection settings please go to appsettings.json file, and change from localhost to other IP or server name. Please be very careful to not open MongoDb directly to the internet. It must be within a secured network.

I have tried to create the project as simple as possible. When you make something bigger than this concise example, yes, it would be a good idea to structure it and make it modular, and easier to maintain.

I usually choose Transient, then scaling up to Scoped or Singleton, when the situation calls for it. There is usually a connection pooling, with an implicit re-using the actual database connections, behind the hood, and for such a simple example, Transient was a better fit.

Scoped services are indeed good, since they can be used to maintain some context during the given request, and they are isolated from other requests happening at the same time. However, the logic of the app would need also to be more extended.

this statement and comments have a problem with an angle brackets. The word between angle brackets dissapears.
Instead of
services.Configure(options =>
Should be
services.Configure OPEN ANGLE BRACKET Settings CLOSE ANGLE BRACKET (options =>

Thanks for the post, Peter. I got one question: I was stuck at the creating user part for mongodb. How could you db.createUser after setting “security authentication” to “enabled”? It throws and error as “not authorized on admin to execute command” every time when I try to creatUser, but if I comment the security line in mongod.conf file, it allows me to create a user. I looked it up but none of the solutions work for me. Do you know why this is happening?

Yes, it is true, and thanks for the hint. I have missed to present this step initially and now I have updated the article.

At first we need to disable the authentication, and create a single user with a superuser role. Then we would stop the server, and enable the authentication. From there, we would connect with this user (“admin” in our case) and we would run any other tasks (query, insert, new user creation etc.).

Thank you for a really good and simple project. I greatly enjoyed building it in Visual Studio 15.
However, there seems to be some problems with both building and running the finished project in Visual Studio 17.
I get a lot of errors with references. I know Microsoft has decided to use *.csproj instead of project.json and all references are stored here from now on. But even when I follow your tutorial and add them manually via NuGet I still get errors. I also cannot use your completed version as it does not work in Visual Studio 17, so I was wondering if you could update your project to be compatable with Visual Studio 17 or maybe add a small section outlining how to do this. It is a really good tutorial and I would very much like to make it work with the latest version Visual Studio Community.