Overview
In this guide, you can learn how to create a ASP.NET Core application that offers OData endpoints and uses the Entity Framework (EF) Core Provider to access MongoDB. ASP.NET Core is a cross-platform framework for creating cloud-based applications. OData is a standardized protocol for building and consuming RESTful APIs, and it allows you to interact with data by using HTTP requests.
The application in this tutorial consists of the following layers:
Database layer: MongoDB provides data storage and retrieval.
Application layer: ASP.NET Core handles HTTP requests, routing, and dependency injection.
Data access layer: The EF Core Provider provides MongoDB document mapping and OData query translation.
Why Use MongoDB with ASP.NET Core and OData?
This tutorial uses the ASP.NET Core OData framework with the Entity Framework (EF) Core Provider for MongoDB to create queryable REST APIs. OData provides a uniform way to expose and interact with data and provides advanced querying capabilities such as filtering, sorting, paging, and field selection.
By integrating MongoDB with ASP.NET Core and OData, you can use EF's familiar patterns alongside MongoDB's flexible document model and OData's query capabilities. This combination supports applications that require complex query interfaces, type safety, and standards-based API design. You can use MongoDB, ASP.NET Core, and OData to create real world applications such as data analytics dashboards, reporting systems, or any application that requires complex data querying.
Quick Start Tutorial
This tutorial shows you how to build an OData REST API that uses MongoDB, ASP.NET Core, and the EF Core Provider. The application accesses sample restaurant data, exposes OData-compliant endpoints, and supports advanced querying capabilities such as filtering, sorting, paging, and field selection. The tutorial also includes instructions for connecting to a MongoDB cluster hosted on MongoDB Atlas.
Tip
If you prefer to connect to MongoDB by using the EF Core Provider without ASP.NET Core, see the Entity Framework Provider Quick Start tutorial.
Set Up Your Project
Follow the steps in this section to install the project dependencies, create an Atlas cluster, and set up the application structure.
Verify the prerequisites.
To create the Quick Start application, install the following software in your development environment:
Prerequisite | Notes |
|---|---|
Install .NET 8.0 or later. | |
Code editor | Use the code editor of your choice. |
Terminal app and shell | For Windows users, use PowerShell or Command Prompt. For macOS/Linux users, use Terminal or a similar app. |
Create a MongoDB Atlas cluster.
MongoDB Atlas is a fully managed cloud database service that hosts your
MongoDB deployments. If you do not have a MongoDB deployment, you can create a MongoDB
cluster for free by completing the
MongoDB Get Started
tutorial. The MongoDB Get Started tutorial also demonstrates how to load sample
datasets into your cluster, including the sample_restaurants database
that is used in this tutorial.
To connect to your MongoDB cluster, you must use a connection string. To learn how to retrieve your connection string, see the Add your connection string section of the MongoDB Get Started tutorial.
Important
Save your connection string in a secure location.
Add the required dependencies.
In your RestaurantODataApi directory, run the following commands to add
the required NuGet packages:
dotnet add package MongoDB.EntityFrameworkCore dotnet add package Microsoft.AspNetCore.OData
These commands install the following packages:
MongoDB.EntityFrameworkCore: The MongoDB EF Core ProviderMicrosoft.AspNetCore.OData: OData support for ASP.NET Core
Configure your database connection.
Navigate to the appsettings.json file in your RestaurantODataApi
project and paste the following code:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "MongoDB": { "ConnectionString": "<connection string>", "DatabaseName": "sample_restaurants" } }
Replace the <connection string> placeholder with the connection string
that you saved from the MongoDB Get Started tutorial.
Create Your Application
After setting up the project structure and dependencies, follow
the steps in this section to create your data models, DbContext,
and OData endpoints.
Create the data models.
In your RestaurantODataApi directory, create a Models subdirectory.
Then, create a file named Restaurant.cs in the Models directory
and add the following code:
using Microsoft.EntityFrameworkCore; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using System.ComponentModel.DataAnnotations; namespace RestaurantODataApi.Models { public class Restaurant { [] [] [] public string Id { get; set; } = string.Empty; [] public string? Name { get; set; } [] public string? Cuisine { get; set; } [] public string? Borough { get; set; } } }
This model class defines the structure of restaurant data from the MongoDB
sample_restaurants.restaurants collection and includes the Entity Framework
and MongoDB serialization attributes.
Configure your database connection.
In your RestaurantODataApi directory, create a file named RestaurantDbContext.cs
and add the following code:
using Microsoft.EntityFrameworkCore; using MongoDB.Driver; using MongoDB.EntityFrameworkCore.Extensions; using RestaurantODataApi.Models; namespace RestaurantODataApi { public class RestaurantDbContext : DbContext { public DbSet<Restaurant> Restaurants { get; set; } public RestaurantDbContext(DbContextOptions<RestaurantDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Configures the Restaurant entity to map to the "restaurants" collection modelBuilder.Entity<Restaurant>().ToCollection("restaurants"); } } }
This class derives from DBContext,
which configures the relationship between your models and the underlying database. The code configures EF
to work with MongoDB and maps the Restaurant entity to the sample_restaurants.restaurants
collection.
Create the OData controller.
In your RestaurantODataApi directory, create a Controllers
subdirectory. Then, add a file named RestaurantsController.cs to
the subdirectory and paste the following code:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.OData.Query; using Microsoft.AspNetCore.OData.Routing.Controllers; using Microsoft.AspNetCore.OData.Routing.Attributes; using RestaurantODataApi.Models; namespace RestaurantODataApi.Controllers { public class RestaurantsController : ODataController { private readonly RestaurantDbContext _context; public RestaurantsController(RestaurantDbContext context) { _context = context; } [] public IQueryable<Restaurant> Get() { return _context.Restaurants; } [] [] public IQueryable<Restaurant> GetRestaurantsByBorough(string borough) { return _context.Restaurants.Where(r => r.Borough == borough); } [] [] public IQueryable<Restaurant> GetRestaurantsByCuisine(string cuisine) { return _context.Restaurants.Where(r => r.Cuisine == cuisine); } } }
This controller defines the following OData REST endpoints:
GET /odata/Restaurants: Retrieves all documents in therestaurantscollection. TheEnableQueryattribute and its configuration options allow you to use OData query parameters, such as$filterand$orderby, in your HTTP requests.GET /odata/GetRestaurantsByBorough(borough='{borough}'): Retrieves documents that have the specifiedboroughvalue.GET /odata/GetRestaurantsByCuisine(cuisine='{cuisine}'): Retrieves documents that have the specifiedcuisinevalue.
Define the application logic.
Navigate to the Program.cs file and replace its contents with the following code:
using Microsoft.AspNetCore.OData; using Microsoft.EntityFrameworkCore; using Microsoft.OData.ModelBuilder; using MongoDB.Driver; using RestaurantODataApi; using RestaurantODataApi.Models; var builder = WebApplication.CreateBuilder(args); // Configures the MongoDB connection var connectionString = builder.Configuration["MongoDB:ConnectionString"]; var databaseName = builder.Configuration["MongoDB:DatabaseName"] ?? "sample_restaurants"; if (string.IsNullOrEmpty(connectionString)) { throw new InvalidOperationException("MongoDB connection string is required. Please set MongoDB:ConnectionString in appsettings.json"); } // Registers a MongoDB client builder.Services.AddSingleton<IMongoClient>(sp => new MongoClient(connectionString)); // Registers the DbContext builder.Services.AddDbContext<RestaurantDbContext>(options => { var mongoClient = new MongoClient(connectionString); options.UseMongoDB(mongoClient, databaseName); }); // Configures the OData EDM model var modelBuilder = new ODataConventionModelBuilder(); modelBuilder.EntitySet<Restaurant>("Restaurants"); modelBuilder.EntityType<Restaurant>().HasKey(r => r.Id); // Registers the unbound functions var getRestaurantsByBoroughFunction = modelBuilder.Function("GetRestaurantsByBorough"); getRestaurantsByBoroughFunction.Parameter<string>("borough"); getRestaurantsByBoroughFunction.ReturnsCollectionFromEntitySet<Restaurant>("Restaurants"); var getRestaurantsByCuisineFunction = modelBuilder.Function("GetRestaurantsByCuisine"); getRestaurantsByCuisineFunction.Parameter<string>("cuisine"); getRestaurantsByCuisineFunction.ReturnsCollectionFromEntitySet<Restaurant>("Restaurants"); // Configures OData with ASP.NET Core builder.Services.AddControllers() .AddOData(opt => opt .AddRouteComponents("odata", modelBuilder.GetEdmModel()) .Select() .Filter() .OrderBy() .Expand() .Count() .SetMaxTop(100)); var app = builder.Build(); app.UseRouting(); app.MapControllers(); app.Run();
This code sets up the MongoDB connection, Entity Framework DbContext,
and OData services. The OData configuration code enables the following
query parameters, which you can use in your HTTP endpoints:
$select: Return the specified fields in the results$filter: Return data based on filter criteria$orderby: Sort the results by a specified field$expand: Include related data in the results$count: Include a count of the results$top: Set the maximum number of results, limited to100
Run Your Application
Finally, follow the steps in this section to run your OData REST API and test the endpoints by using HTTP requests.
Start the ASP.NET Core application.
From your RestaurantODataApi directory, run the following command to compile and
start the application:
dotnet run
If successful, your command output resembles the following example:
info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5236 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down.
Test your OData endpoints.
In a separate terminal, run the following curl commands to test the OData endpoints.
Each endpoint returns JSON data in OData format that includes restaurant information from the
sample_restaurants.restaurants collection. If successful, your curl commands return
data similar to the sample outputs provided. The commands also limit
the results to 5 documents.
Retrieve all restaurants.
curl 'http://localhost:5236/odata/Restaurants?$top=5' {"@odata.context":"http://localhost:5236/odata/$metadata#Restaurants", "value":[ {"Id":"...","Name":"Riviera Caterer","Cuisine": "American","Borough":"Brooklyn","RestaurantId":"40356018"}, {"Id":"...","Name":"Wilken'S Fine Food","Cuisine": "Delicatessen","Borough":"Brooklyn","RestaurantId":"40356483"}, {"Id":"...","Name":"Kosher Island","Cuisine": "Jewish/Kosher","Borough":"Staten Island","RestaurantId":"40356442"}, {"Id":"...","Name":"Wendy'S","Cuisine":"Hamburgers", "Borough":"Brooklyn","RestaurantId":"30112340"}, {"Id":"...","Name":"Morris Park Bake Shop","Cuisine": "Bakery","Borough":"Bronx","RestaurantId":"30075445"} ]} Filter restaurants by borough.
The following command retrieves restaurants that have a
boroughvalue of"Queens":curl 'http://localhost:5236/odata/GetRestaurantsByBorough(borough=%27Queens%27)?$top=5' {"@odata.context":"http://localhost:5236/odata/$metadata#Restaurants", "value":[ {"Id":"...","Name":"Tov Kosher Kitchen","Cuisine":"Jewish/Kosher", "Borough":"Queens","RestaurantId":"40356068"}, {"Id":"...","Name":"Brunos On The Boulevard","Cuisine":"American", "Borough":"Queens","RestaurantId":"40356151"}, {"Id":"...","Name":"Carvel Ice Cream","Cuisine":"Ice Cream, Gelato, Yogurt, Ices", "Borough":"Queens","RestaurantId":"40361322"}, {"Id":"...","Name":"Sal'S Deli","Cuisine":"Delicatessen", "Borough":"Queens","RestaurantId":"40361618"}, {"Id":"...","Name":"Steve Chu'S Deli & Grocery","Cuisine":"Delicatessen", "Borough":"Queens","RestaurantId":"40361998"} ]} Filter restaurants by cuisine.
The following command retrieves restaurants that have a
cuisinevalue of"Mexican":curl 'http://localhost:5236/odata/GetRestaurantsByCuisine(cuisine=%27Mexican%27)?$top=5' {"@odata.context":"http://localhost:5236/odata/$metadata#Restaurants", "value":[ {"Id":"...","Name":"Panchito'S","Cuisine":"Mexican","Borough":"Manhattan"}, {"Id":"...","Name":"Mexico Lindo Restaurant","Cuisine":"Mexican","Borough":"Manhattan"}, {"Id":"...","Name":"Casa Pepe","Cuisine":"Mexican","Borough":"Brooklyn"}, {"Id":"...","Name":"Cuchifrito","Cuisine":"Mexican","Borough":"Manhattan"}, {"Id":"...","Name":"Mary Ann'S","Cuisine":"Mexican","Borough":"Manhattan"} ]}
Test OData's advanced query capabilities.
You can use the endpoints to run complex queries by including
OData query parameters and operators. The following curl commands
test these capabilities.
Filter by multiple fields.
The following command uses OData query operators to retrieve documents that have a
boroughvalue of"Queens"and anamevalue that contains"Moon":curl 'http://localhost:5236/odata/Restaurants?$filter=Borough%20eq%20%27Queens%27%20and%20contains(Name,%20%27Moon%27)' {"@odata.context":"http://localhost:5236/odata/$metadata#Restaurants", "value":[ {"Id":"...","Name":"New Moon Star Restaurant","Cuisine":"Chinese","Borough":"Queens"}, {"Id":"...","Name":"Moon Tikka Grill","Cuisine":"Indian","Borough":"Queens"}, {"Id":"...","Name":"Silver Moon Diner","Cuisine":"American","Borough":"Queens"}, {"Id":"...","Name":"Mooney'S Public House","Cuisine":"Irish","Borough":"Queens"}, {"Id":"...","Name":"Moon Light Crill Rest","Cuisine":"Indian","Borough":"Queens"}, {"Id":"...","Name":"Full Moon Cafe","Cuisine":"Café/Coffee/Tea","Borough":"Queens"}, {"Id":"...","Name":"Pacific Moon","Cuisine":"Chinese","Borough":"Queens"}, {"Id":"...","Name":"Moon Palace Kitchen","Cuisine":"Chinese","Borough":"Queens"}, {"Id":"...","Name":"Honey Moon Coffee Shop","Cuisine":"Café/Coffee/Tea","Borough":"Queens"}, {"Id":"...","Name":"Honey Moon Coffee Shop","Cuisine":"Café/Coffee/Tea","Borough":"Queens"} ]}% Order and count your results.
The following command sorts documents that match the
cuisinefilter by theirnamevalue and counts the total number of matching documents:curl 'http://localhost:5236/odata/GetRestaurantsByCuisine(cuisine=%27Czech%27)?$orderby=Name&$count=true' {"@odata.context":"http://localhost:5236/odata/$metadata#Restaurants", "@odata.count":6, "value":[ {"Id":"...","Name":"Bohemian Beer Garden","Cuisine":"Czech","Borough":"Queens"}, {"Id":"...","Name":"Brooklyn Beet Company","Cuisine":"Czech","Borough":"Brooklyn"}, {"Id":"...","Name":"Hospoda","Cuisine":"Czech","Borough":"Manhattan"}, {"Id":"...","Name":"Koliba Restaurant","Cuisine":"Czech","Borough":"Queens"}, {"Id":"...","Name":"Milan'S Restaurant","Cuisine":"Czech","Borough":"Brooklyn"}, {"Id":"...","Name":"Olde Prague Tavern","Cuisine":"Czech","Borough":"Queens"} ]}
Congratulations on completing the EF, ASP.NET, and OData Quick Start tutorial! After you complete these steps, you have an ASP.NET Core OData REST API that connects to your MongoDB deployment, returns restaurant data by using OData endpoints, and supports advanced query capabilities like filtering, sorting, paging, field selection, and searching.
Additional Resources
To learn more about the concepts mentioned in this tutorial, see the following resources:
ASP.NET Core OData documentation
OData Protocol documentation
MongoDB Entity Framework Core Provider documentation
MongoDB C# Driver documentation