| title | Create a web API with ASP.NET Core and MongoDB |
|---|---|
| author | wadepickett |
| <!-- author | prkhandelwal --> |
| description | This tutorial demonstrates how to create an ASP.NET Core web API using a MongoDB NoSQL database. |
| monikerRange | >= aspnetcore-3.1 |
| ms.author | wpickett |
| ms.custom | mvc |
| ms.date | 04/09/2025 |
| uid | tutorials/first-mongo-app |
By Pratik Khandelwal and Scott Addie
:::moniker range=">= aspnetcore-9.0"
This tutorial creates a web API that runs Create, Read, Update, and Delete (CRUD) operations on a MongoDB NoSQL database.
In this tutorial, you learn how to:
[!div class="checklist"]
- Configure MongoDB
- Create a MongoDB database
- Define a MongoDB collection and schema
- Perform MongoDB CRUD operations from a web API
- Customize JSON serialization
Enable MongoDB and MongoDB Shell access from anywhere on the development machine (Windows/Linux/macOS):
-
Download and Install MongoDB Shell:
- macOS/Linux: Choose a directory to extract the MongoDB Shell to. Add the resulting path for
mongoshto thePATHenvironment variable. - Windows: MongoDB Shell (mongosh.exe) is installed at C:\Users\<user>\AppData\Local\Programs\mongosh. Add the resulting path for
mongosh.exeto thePATHenvironment variable.
- macOS/Linux: Choose a directory to extract the MongoDB Shell to. Add the resulting path for
-
Download and Install MongoDB:
- macOS/Linux: Verify the directory that MongoDB was installed at, usually in /usr/local/mongodb. Add the resulting path for
mongodbto thePATHenvironment variable. - Windows: MongoDB is installed at C:\Program Files\MongoDB by default. Add C:\Program Files\MongoDB\Server\<version_number>\bin to the
PATHenvironment variable.
- macOS/Linux: Verify the directory that MongoDB was installed at, usually in /usr/local/mongodb. Add the resulting path for
-
Choose a Data Storage Directory: Select a directory on your development machine for storing data. Create the directory if it doesn't exist. The MongoDB Shell doesn't create new directories:
- macOS/Linux: For example,
/usr/local/var/mongodb. - Windows: For example,
C:\\BooksData.
- macOS/Linux: For example,
-
In the OS command shell (not the MongoDB Shell), use the following command to connect to MongoDB on default port 27017. Replace
<data_directory_path>with the directory chosen in the previous step.mongod --dbpath <data_directory_path>
Use the previously installed MongoDB Shell in the following steps to create a database, make collections, and store documents. For more information on MongoDB Shell commands, see mongosh.
-
Open a MongoDB command shell instance by launching
mongosh.exe, or by running the following command in the command shell:mongosh -
In the command shell connect to the default test database by running:
use BookStoreA database named BookStore is created if it doesn't already exist. If the database does exist, its connection is opened for transactions.
-
Create a
Bookscollection using following command:db.createCollection('Books')The following result is displayed:
{ "ok" : 1 } -
Define a schema for the
Bookscollection and insert two documents using the following command:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])A result similar to the following is displayed:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
[!NOTE] The
ObjectIds shown in the preceding result won't match those shown in the command shell. -
View the documents in the database using the following command:
db.Books.find().pretty()A result similar to the following is displayed:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
The schema adds an autogenerated
_idproperty of typeObjectIdfor each document.
- Go to File > New > Project.
- Select the ASP.NET Core Web API project type, and select Next.
- Name the project BookStoreApi, and select Next.
- In the Additional information dialog:
- Confirm the Framework is .NET 9.0 (Standard Term Support).
- Confirm the checkbox for Use controllers is checked.
- Confirm the checkbox for Enable OpenAPI support is checked.
- Select Create.
-
In the Package Manager Console window, navigate to the project root. Run the following command to install the .NET driver for MongoDB:
Install-Package MongoDB.Driver
-
Run the following commands in a command shell:
dotnet new webapi -o BookStoreApi --use-controllers code BookStoreApiThe preceding commands generate a new ASP.NET Core web API project and then open the project in Visual Studio Code.
-
Once the OmniSharp server starts up, a dialog asks Required assets to build and debug are missing from 'BookStoreApi'. Add them?. Select Yes.
-
Open the Integrated Terminal and run the following command to install the .NET driver for MongoDB:
dotnet add package MongoDB.Driver
-
Add a Models directory to the project root.
-
Add a
Bookclass to the Models directory with the following code::::code language="csharp" source="first-mongo-app/samples_snapshot/9.x/Book.cs":::
In the preceding class, the
Idproperty is:- Required for mapping the Common Language Runtime (CLR) object to the MongoDB collection.
- Annotated with
[BsonId]to make this property the document's primary key. - Annotated with
[BsonRepresentation(BsonType.ObjectId)]to allow passing the parameter as typestringinstead of an ObjectId structure. Mongo handles the conversion fromstringtoObjectId.
The
BookNameproperty is annotated with the[BsonElement]attribute. The attribute's value ofNamerepresents the property name in the MongoDB collection.
-
Add the following database configuration values to
appsettings.json::::code language="json" source="first-mongo-app/samples/9.x/BookStoreApi/appsettings.json" highlight="2-6":::
-
Add a
BookStoreDatabaseSettingsclass to the Models directory with the following code::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Models/BookStoreDatabaseSettings.cs":::
The preceding
BookStoreDatabaseSettingsclass is used to store theappsettings.jsonfile'sBookStoreDatabaseproperty values. The JSON and C# property names are named identically to ease the mapping process. -
Add the following highlighted code to
Program.cs::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_BookStoreDatabaseSettings" highlight="4-5":::
In the preceding code, the configuration instance to which the
appsettings.jsonfile'sBookStoreDatabasesection binds is registered in the Dependency Injection (DI) container. For example, theBookStoreDatabaseSettingsobject'sConnectionStringproperty is populated with theBookStoreDatabase:ConnectionStringproperty inappsettings.json. -
Add the following code to the top of
Program.csto resolve theBookStoreDatabaseSettingsreference::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_UsingModels":::
-
Add a Services directory to the project root.
-
Add a
BooksServiceclass to the Services directory with the following code::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Services/BooksService.cs" id="snippet_File":::
In the preceding code, a
BookStoreDatabaseSettingsinstance is retrieved from DI via constructor injection. This technique provides access to theappsettings.jsonconfiguration values that were added in the Add a configuration model section. -
Add the following highlighted code to
Program.cs::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_BooksService" highlight="7":::
In the preceding code, the
BooksServiceclass is registered with DI to support constructor injection in consuming classes. The singleton service lifetime is most appropriate becauseBooksServicetakes a direct dependency onMongoClient. Per the official Mongo Client reuse guidelines,MongoClientshould be registered in DI with a singleton service lifetime. -
Add the following code to the top of
Program.csto resolve theBooksServicereference::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_UsingServices":::
The BooksService class uses the following MongoDB.Driver members to run CRUD operations against the database:
-
MongoClient: Reads the server instance for running database operations. The constructor of this class is provided in the MongoDB connection string:
:::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Services/BooksService.cs" id="snippet_ctor" highlight="4-5":::
-
IMongoDatabase: Represents the Mongo database for running operations. This tutorial uses the generic GetCollection<TDocument>(collection) method on the interface to gain access to data in a specific collection. Run CRUD operations against the collection after this method is called. In the
GetCollection<TDocument>(collection)method call:collectionrepresents the collection name.TDocumentrepresents the CLR object type stored in the collection.
GetCollection<TDocument>(collection) returns a MongoCollection object representing the collection. In this tutorial, the following methods are invoked on the collection:
- DeleteOneAsync: Deletes a single document matching the provided search criteria.
- Find<TDocument>: Returns all documents in the collection matching the provided search criteria.
- InsertOneAsync: Inserts the provided object as a new document in the collection.
- ReplaceOneAsync: Replaces the single document matching the provided search criteria with the provided object.
Add a BooksController class to the Controllers directory with the following code:
:::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Controllers/BooksController.cs":::
The preceding web API controller:
- Uses the
BooksServiceclass to run CRUD operations. - Contains action methods to support GET, POST, PUT, and DELETE HTTP requests.
- Calls xref:Microsoft.AspNetCore.Mvc.ControllerBase.CreatedAtAction%2A in the
Createaction method to return an HTTP 201 response. Status code 201 is the standard response for an HTTP POST method that creates a new resource on the server.CreatedAtActionalso adds aLocationheader to the response. TheLocationheader specifies the URI of the newly created book.
There are two details to change about the JSON responses returned in the Test the web API section:
- The property names' default camel casing should be changed to match the Pascal casing of the CLR object's property names.
- The
bookNameproperty should be returned asName.
To satisfy the preceding requirements, make the following changes:
-
In
Program.cs, chain the following highlighted code on to theAddControllersmethod call::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_AddControllers" highlight="10-11":::
With the preceding change, property names in the web API's serialized JSON response match their corresponding property names in the CLR object type. For example, the
Bookclass'sAuthorproperty serializes asAuthorinstead ofauthor. -
In
Models/Book.cs, annotate theBookNameproperty with the[JsonPropertyName]attribute::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Models/Book.cs" id="snippet_BookName" highlight="2":::
The
[JsonPropertyName]attribute's value ofNamerepresents the property name in the web API's serialized JSON response. -
Add the following code to the top of
Models/Book.csto resolve the[JsonProperty]attribute reference::::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Models/Book.cs" id="snippet_UsingSystemTextJsonSerialization":::
-
Repeat the steps defined in the Test the web API section. Notice the difference in JSON property names.
This tutorial uses Endpoints Explorer and .http files to test the API.
-
Build and run the app.
-
In Endpoints Explorer, right-click the first GET endpoint
/api/books, and select Generate request.The following content is added to the
BookStoreApi.httpfile. If this is the first time that a request is generated, the file is created in the project root.@BookStoreApi_HostAddress = https://localhost:<port> GET {{BookStoreApi_HostAddress}}/api/books ###The port number should already be set to the port used by the app, for example,
https://localhost:56874. If that's not the case you can find your port number in the output window when you launch the app. -
Select the Send request link above the new
GETrequest line.The GET request is sent to the app and the response is displayed in the Response pane.
-
The response body shows the JSON result containing the book entries similar to the following:
[ { "Id": "61a6058e6c43f32854e51f51", "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" } ] -
To retrieve a single book, right-click the
/api/books/{id}, params (string id)GET endpoint in the Endpoints Explorer, and select Generate request.The following content is appended to the
BookStoreApi.httpfile:@id=string GET {{BookStoreApi_HostAddress}}/api/books/{{id}} ### -
Replace
idvariable with one of the IDs returned from the earlier request, for example:@id="61a6058e6c43f32854e51f52" GET {{BookStoreApi_HostAddress}}/api/books/{{id}} ### -
Select the Send request link above the new
GETrequest line.The GET request is sent to the app and the response is displayed in the Response pane.
-
The response body shows JSON similar to the following:
{ "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" } -
To test the POST endpoint, right-click the
/api/booksPOST endpoint and select Generate request.The following content is added to the
BookStoreApi.httpfile:POST {{BookStoreApi_HostAddress}}/api/books Content-Type: application/json { //Book } ### -
Replace the Book comment with a book object as the JSON request body:
POST {{BookStoreApi_HostAddress}}/api/books Content-Type: application/json { "Name": "The Pragmatic Programmer", "Price": 49.99, "Category": "Computers", "Author": "Andy Hunt" } ### -
Select the Send request link above the
POSTrequest line.The POST request is sent to the app, and the response is displayed in the Response pane. The response should include the newly created book with its assigned ID.
-
Lastly, to delete a book, right-click the
/api/books/{id}, params (string id)DELETE endpoint and select Generate request.The following content is appended to the
BookStoreApi.httpfile:DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}} ### -
Replace the
idvariable with one of the IDs returned from the earlier request, and click Send request. For example:DELETE {{BookStoreApi_HostAddress}}/api/Books/67f417517ce1b36aeab71236 ###
This tutorial uses the OpenAPI specification (openapi.json) and Swagger UI to test the API.
- Install Swagger UI by running the following command:
dotnet add package NSwag.AspNetCore
The previous command adds the NSwag.AspNetCore package, which contains tools to generate Swagger documents and UI. Because our project is using OpenAPI, we only use the NSwag package to generate the Swagger UI.
- Configure Swagger middleware
In Program.cs, add the following highlighted code:
:::code language="csharp" source="first-mongo-app/samples/9.x/BookStoreApi/Program.cs" id="snippet_UseSwagger" highlight="6-9":::
The previous code enables the Swagger middleware for serving the generated JSON document using the Swagger UI. Swagger is only enabled in a development environment. Enabling Swagger in a production environment could expose potentially sensitive details about the API's structure and implementation.
The app uses the OpenAPI document generated by OpenApi, located at /openapi/v1.json, to generate the UI.
View the generated OpenAPI specification for the WeatherForecast API while the project is running by navigating to https://localhost:<port>/openapi/v1.json in your browser.
The OpenAPI specification is a document in JSON format that describes the structure and capabilities of your API, including endpoints, request/response formats, parameters, and more. It's essentially a blueprint of your API that can be used by various tools to understand and interact with your API.
-
Build and run the app.
-
Navigate to
https://localhost:<port>/swaggerin your browser. Swagger provides a UI to test all the API endpoints based on the OpenAPI document. -
Expand the GET /api/books endpoint and click the Try it out button.
-
Click the Execute button to send the request to the API.
-
The Response body section displays a JSON array with books similar to the following:
[ { "Id": "61a6058e6c43f32854e51f51", "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" } ] -
Next, expand the GET /api/books/{id} endpoint and click Try it out.
-
Enter one of the book IDs from the previous response in the id field, then click Execute.
-
The Response body section displays the JSON object for the specified book. For example, the result for the ID
61a6058e6c43f32854e51f52is similar to the following:{ "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" } -
To test creating a new book, expand the POST /api/books endpoint and click Try it out.
-
Replace the default request body with a new book object:
{ "Name": "The Pragmatic Programmer", "Price": 49.99, "Category": "Computers", "Author": "Andy Hunt" } -
Click Execute to send the request.
-
The response should have a status code of 201 (Created) and include the newly created book with its assigned ID in the response body.
-
Lastly, to delete a book record, expand the DELETE /api/books/{id} endpoint, click Try it out, and enter one of the book IDs from the previous response in the id field. Click Execute to send the request.
-
The response should have a status code of 204 (No Content), indicating that the book was successfully deleted.
- View or download sample code (how to download)
- xref:web-api/index
- xref:web-api/action-return-types
- Create a web API with ASP.NET Core
:::moniker-end