How to create a Web API with ASP.NET and MongoDB
Tags: dotnet, mongodb, aspnet
Published: 2021-12-19 20:11:55

In this tutorial, you will learn how to create a Web API with ASP.NET and MongoDB. We will create an API that allows CRUD operations on a movie database.

# What is MongoDB?

MongoDB is a document-based NoSQL database. Unlike a relational database, which stores data in tables, MongoDB stores data as documents that are organized into collections.

# Tools

- [Visual Studio 2022](https://visualstudio.microsoft.com)
- [Postman](https://www.postman.com/)
- [MongoDB](https://www.mongodb.com)
- [MongoDB Compass](https://www.mongodb.com/products/compass)

# Creating the database

I’m going to work with MongoDB on my local computer. To install an instance of the MongoDB server follow the link below.

[Install MongoDB](https://docs.mongodb.com/manual/installation/)

> If you don't want to use MongoDB on your local machine, you can always use MongoDB Atlas. MongoDB Atlas  is a database as a service, and you can try it for free.
> 

1. Launch MongoDB Compass.
2. Click on the "Connect" button to connect to your local server.
3. Once connected to the server, click on the **Create Database** button to create a new database.
4. In the dialog, set the database name to **MoviesDb** and set the collection name to **MoviesCollection**.
5. Click on **Create Database** button to generate the database.

# Creating the ASP.NET Application

1. Launch Visual Studio 2022.
2. Go to file -> new -> Project.
3. Select **ASP.NET Empty template**, then click on the **Next** button.
4. Set the project's name to **MoviesAPI**.
5. Select **.NET 6** as the framework and unselect **configure with HTTPS** then click on the **Create** button to generate the project.

# Installing the MongoDB .NET driver

This is the official .NET driver for MongoDB, it will help connect to MongoDB.

1. Open the NuGet Package Manager UI in Visual Studio.
2. Search for **MongoDB.Driver**, select and install.

# Configuration

1. To connect to MongoDB, we will need some details like the connection string, the database name, and the collection name. We will store these details in the application configuration file.
    
    ```
    "MoviesDatabaseSettings": {
      "ConnectionString": "Your connection string to MongoDB",
      "DatabaseName": "MoviesDb",
      "MoviesCollectionName": "Movies"
    }
    
    ```
    

<aside>
💡 To get the connection string for your database, disconnect from MongoDB Compass, and the connection string will be displayed on the home window of the application.

</aside>

2. To read this section in the application, we will use the options pattern. Add a new class named **MoviesDatabaseSettings**.
    
    ```
    public class MoviesDatabaseSettings
    {
        public string ConnectionString { get; set; } = string.Empty;
        public string DatabaseName { get; set; } = string.Empty;
        public string MoviesCollectionName { get; set; } = string.Empty;
    }
    
    ```
    
    ASP.NET will map the section "MoviesDatabaseSettings" to this class.
    
3. In program.cs, after a WebApplication is instantiated, we register the **MoviesDatabaseSettings** class with the dependency injection container.
    
    ```
    builder.Services.Configure<MoviesDatabaseSettings>(builder.Configuration.GetSection("MoviesDatabaseSettings"));
    
    ```
    
    > Make sure, you install the following Nuget package: Microsoft.Extensions.Options
    > 

# Creating the model

Add a new class like the one below:

```
 public class Movie
 {
     [BsonId]
     [BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]
     public string Id { get; set; }
     public string Title { get; set; }
     public int Year { get; set; }
     public string Summary { get; set; } = null;
     public List<string> Actors { get; set; }
 }

```

- The Id property is decorated with the **BsonId** attribute to mark it as the primary key.
- MongoDB stores the primary key in an **ObjectId** structure, to tell MongoDB that it needs to convert from string to ObjectId, the Id property is also decorated with the attribute **BsonRepresentation**.

# Creating CRUD operations in a service

1. Add a new class, paste the following code:
    
    ```
    public class MoviesService
    {
        private readonly IMongoCollection<Movie> _movies;
    
        public MoviesService(IOptions<MoviesDatabaseSettings> options)
        {
            var mongoClient = new MongoClient(options.Value.ConnectionString);
    
            _movies = mongoClient.GetDatabase(options.Value.DatabaseName)
                .GetCollection<Movie>(options.Value.MoviesCollectionName);
        }
    
        public async Task<List<Movie>> Get() =>
            await _movies.Find(_ => true).ToListAsync();
    
        public async Task<Movie> Get(string id) =>
            await _movies.Find(m => m.Id == id).FirstOrDefaultAsync();
    
        public async Task Create(Movie newMovie) =>
            await _movies.InsertOneAsync(newMovie);
    
        public async Task Update(string id, Movie updateMovie) =>
            await _movies.ReplaceOneAsync(m => m.Id == id, updateMovie);
    
        public async Task Remove(string id) =>
            await _movies.DeleteOneAsync(m => m.Id == id);
    }
    
    ```
    
    **MongoClient** is responsible for running database operations.
    
2. Register the service with the dependency injection container.
    
    ```
    builder.Services.AddSingleton<MoviesService>();
    
    ```
    
    **MoviesService** is registered as a singleton because the service depends on the **MongoClient**, it is recommended to use the **MongoClient** as a singleton.
    

# Creating endpoints for CRUD operations

Update the program.cs to look like this:

```
using MoviesAPI.Data;

var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MoviesDatabaseSettings>(builder.Configuration.GetSection("MoviesDatabaseSettings"));
builder.Services.AddSingleton<MoviesService>();
var app = builder.Build();

app.MapGet("/", () => "Movies API!");

app.MapGet("/api/movies", async(MoviesService moviesService) => await moviesService.Get());

app.MapGet("/api/movies/{id}", async(MoviesService moviesService, string id) =>
{
    var movie = await moviesService.Get(id);
    return movie is null ? Results.NotFound() : Results.Ok(movie);
});

app.MapPost("/api/movies", async (MoviesService moviesService, Movie movie) =>
{
    await moviesService.Create(movie);
    return Results.Ok();
});

app.MapPut("/api/movies/{id}", async(MoviesService moviesService, string id, Movie updatedMovie) =>
{
    var movie = await moviesService.Get(id);
    if (movie is null) return Results.NotFound();

    updatedMovie.Id = movie.Id;
    await moviesService.Update(id, updatedMovie);

    return Results.NoContent();
});

app.MapDelete("/api/movies/{id}", async (MoviesService moviesService, string id) =>
{
    var movie = await moviesService.Get(id);
    if (movie is null) return Results.NotFound();

    await moviesService.Remove(movie.Id);

    return Results.NoContent();
});

app.Run();

```

Creating, Reading, Updating, and deleting actions will be mapped to HTTP verbs such as POST, GET, PUT, and DELETE.
I am using the Minimal API syntax to create each endpoint. For an HTTP verb, We need to declare a route and a route handler that will handle a request to the route. Because we registered the MoviesService with the dependency injection container, it can be injected in each route handler.

# Testing the API

If you want to add a new movie for instance.

1. Start Debugging the application or press F5.
2. Copy the URL displayed in the web browser.
3. Launch POSTMAN.
4. Create a new request then select POST as HTTP verb.
5. In the address bar, paste the URL then add "/api/movies".
6. In the Body section, paste the following json as the payload.

```
	{
		"Title":  "The Shawshank Redemption",
		"Year":  1994,
		"Summary":  "Banker Andy Dufresne is arrested for killing his wife and her lover. After a hard adjustment, he tries to improve the conditions of the prison and to give hope to his companions.",
		"Actors":  ["tim robbins","morgan freeman"]
	}

```

1. Click on the **SEND** button.
2. You should get a 200 status code as the response.

# Happy coding !!!

Here's the tutorial in video:

{% youtube VSsAsA6_-GE  %}