Tutorial: Develop an ASP.NET web application with Azure Cosmos DB for NoSQL
APPLIES TO: NoSQL
The Azure SDK for .NET allows you to query data in an API for NoSQL container using LINQ in C# or a SQL query string. This tutorial will walk through the process of updating an existing ASP.NET web application that uses placeholder data to instead query from the API.
In this tutorial, you learn how to:
- Create and populate a database and container using API for NoSQL
- Create an ASP.NET web application from a template
- Query data from the API for NoSQL container using the Azure SDK for .NET
Prerequisites
- An existing Azure Cosmos DB for NoSQL account.
- If you have an Azure subscription, create a new account.
- If you don't have an Azure subscription, create a Trial Subscription before you begin.
- Visual Studio Code
- .NET 6 (LTS) or later
- Experience writing C# applications.
Create API for NoSQL resources
First, you'll create a database and container in the existing API for NoSQL account. You'll then populate this account with data using the cosmicworks
dotnet tool.
Navigate to your existing API for NoSQL account in the Azure portal.
In the resource menu, select Keys.
On the Keys page, observe and record the value of the PRIMARY CONNECTION STRING* field. This value will be used throughout the tutorial.
In the resource menu, select Data Explorer.
On the Data Explorer page, select the New Container option in the command bar.
In the New Container dialog, create a new container with the following settings:
Setting Value Database id cosmicworks
Database throughput type Manual Database throughput amount 1000
Container id products
Partition key /category/name
Important
In this tutorial, we will first scale the database up to 1,000 RU/s in shared throughput to maximize performance for the data migration. Once the data migration is complete, we will scale down to 400 RU/s of provisioned throughput.
Select OK to create the database and container.
Open a terminal to run commands to populate the container with data.
Tip
You can optionally use the Azure Cloud Shell here.
Install v2 of the
cosmicworks
dotnet tool from NuGet.dotnet tool install --global cosmicworks --version 2.*
Use the
cosmicworks
tool to populate your API for NoSQL account with sample product data using the URI and PRIMARY KEY values you recorded earlier in this lab. Those recorded values will be used for theendpoint
andkey
parameters respectively.cosmicworks \ --number-of-products 1759 \ --number-of-employees 0 \ --disable-hierarchical-partition-keys \ --connection-string <nosql-connection-string>
Observe the output from the command line tool. It should add 1759 items to the container. The example output included is truncated for brevity.
── Parsing connection string ──────────────────────────────────────────────────────────────── ╭─Connection string──────────────────────────────────────────────────────────────────────────╮ │ AccountEndpoint=https://<account-name>.documents.azure.cn:443/;AccountKey=<account-key>; │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ── Populating data ────────────────────────────────────────────────────────────────────────── ╭─Products configuration─────────────────────────────────────────────────────────────────────╮ │ Database cosmicworks │ │ Container products │ │ Count 1,759 │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ... [SEED] 00000000-0000-0000-0000-000000005951 | Road-650 Black, 60 - Bikes [SEED] 00000000-0000-0000-0000-000000005950 | Mountain-100 Silver, 42 - Bikes [SEED] 00000000-0000-0000-0000-000000005949 | Men's Bib-Shorts, L - Clothing [SEED] 00000000-0000-0000-0000-000000005948 | ML Mountain Front Wheel - Components [SEED] 00000000-0000-0000-0000-000000005947 | Mountain-500 Silver, 42 - Bikes
Return to the Data Explorer page for your account.
In the Data section, expand the
cosmicworks
database node and then select Scale.Reduce the throughput from 1,000 down to 400.
In the command bar, select Save.
In the Data section, expand and select the products container node.
In the command bar, select New SQL query.
In the query editor, add this SQL query string.
SELECT p.sku, p.price FROM products p WHERE p.price < 2000 ORDER BY p.price DESC
Select Execute Query to run the query and observe the results.
The results should be a paginated array of all items in the container with a
price
value that is less than 2,000 sorted from highest price to lowest. For brevity, a subset of the output is included here.[ { "sku": "BK-R79Y-48", "price": 1700.99 }, ... { "sku": "FR-M94B-46", "price": 1349.6 }, ...
Replace the content of the query editor with this query and then select Execute Query again to observe the results.
SELECT p.name, p.category.name AS category, p.category.subCategory.name AS subcategory, p.tags FROM products p JOIN tag IN p.tags WHERE STRINGEQUALS(tag, "yellow", true)
The results should be a smaller array of items filtered to only contain items that include at least one tag with a name value of
Tag-32
. Again, a subset of the output is included here for brevity.[ ... { "name": "HL Touring Frame - Yellow, 60", "category": "Components", "subcategory": "Touring Frames", "tags": [ "Components", "Touring Frames", "Yellow", "60" ] }, ... ]
Create ASP.NET web application
Now, you'll create a new ASP.NET web application using a sample project template. You'll then explore the source code and run the sample to get acquainted with the application before adding Azure Cosmos DB connectivity using the Azure SDK for .NET.
Important
This tutorial transparently pulls packages from NuGet. You can use dotnet nuget list source
to verify your package sources. If you do not have NuGet as a package source, use dotnet nuget add source
to install the site as a source.
Open a terminal in an empty directory.
Install the
cosmicworks.template.web
project template package from NuGet.dotnet new install cosmicworks.template.web
Create a new web application project using the newly installed
dotnet new cosmosdbnosql-webapp
template.dotnet new cosmosdbnosql-webapp
Build and run the web application project.
dotnet run
Observe the output of the run command. The output should include a list of ports and URLs where the application is running.
... info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production ...
Open a new browser and navigate to the running web application. Observe all three pages of the running application.
Stop the running application by terminating the running process.
Tip
Use the Ctrl+C command to stop a running process.Alternatively, you can close and re-open the terminal.
Open Visual Studio Code using the current project folder as the workspace.
Tip
You can run
code .
in the terminal to open Visual Studio Code and automatically open the working directory as the current workspace.Navigate to and open the Services/ICosmosService.cs file. Observe the
RetrieveActiveProductsAsync
andRetrieveAllProductsAsync
default method implementations. These methods create a static list of products to use when running the project for the first time. A truncated example of one of the methods is provided here.public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync() { await Task.Delay(1); return new List<Product>() { new Product(id: "baaa4d2d-5ebe-45fb-9a5c-d06876f408e0", category: new Category(name: "Components, Road Frames"), sku: "FR-R72R-60", name: """ML Road Frame - Red, 60""", description: """The product called "ML Road Frame - Red, 60".""", price: 594.83000000000004m), new Product(id: "bd43543e-024c-4cda-a852-e29202310214", category: new Category(name: "Components, Forks"), sku: "FK-5136", name: """ML Fork""", description: """The product called "ML Fork".""", price: 175.49000000000001m), ... }; }
Navigate to and open the Services/CosmosService.cs file. Observe the current implementation of the CosmosService class. This class implements the ICosmosService interface but doesn't override any methods. In this context, the class will use the default interface implementation until an override of the implementation is provided in the interface.
public class CosmosService : ICosmosService { }
Finally, navigate to and open the Models/Product.cs and Models/Category.cs files. Observe the record types defined in each file. These types will be used in queries throughout this tutorial.
public record Product( string id, Category category, string sku, string name, string description, decimal price );
public record Category( string name );
Query data using the .NET SDK
Next, you'll add the Azure SDK for .NET to this sample project and use the library to query data from the API for NoSQL container.
Back in the terminal, add the
Microsoft.Azure.Cosmos
package from NuGet.dotnet add package Microsoft.Azure.Cosmos
Build the project.
dotnet build
Back in Visual Studio Code, navigate again to the Services/CosmosService.cs file.
Add a new using directive for the
Microsoft.Azure.Cosmos
andMicrosoft.Azure.Cosmos.Linq
namespaces.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq;
Within the CosmosService class, add a new
private readonly
member of typeCosmosClient
named_client
.private readonly CosmosClient _client;
Create a new empty constructor for the
CosmosService
class.public CosmosService() { }
Within the constructor, create a new instance of the
CosmosClient
class passing in a string parameter with the PRIMARY CONNECTION STRING value you previously recorded in the lab. Store this new instance in the_client
member.public CosmosService() { _client = new CosmosClient( connectionString: "<primary-connection-string>" ); }
Back within the CosmosService class, create a new
private
property of typeContainer
namedcontainer
. Set the get accessor to return thecosmicworks
database andproducts
container.private Container container { get => _client.GetDatabase("cosmicworks").GetContainer("products"); }
Create a new asynchronous method named
RetrieveAllProductsAsync
that returns anIEnumerable<Product>
.public async Task<IEnumerable<Product>> RetrieveAllProductsAsync() { }
For the next steps, add this code within the
RetrieveAllProductsAsync
method.Use the
GetItemLinqQueryable<>
generic method to get an object of typeIQueryable<>
that you can use to construct a Language-integrated query (LINQ). Store that object in a variable namedqueryable
.var queryable = container.GetItemLinqQueryable<Product>();
Construct a LINQ query using the
Where
andOrderByDescending
extension methods. Use theToFeedIterator
extension method to create an iterator to get data from Azure Cosmos DB and store the iterator in a variable namedfeed
. Wrap this entire expression in a using statement to dispose the iterator later.using FeedIterator<Product> feed = queryable .Where(p => p.price < 2000m) .OrderByDescending(p => p.price) .ToFeedIterator();
Create a new variable named
results
using the genericList<>
type.List<Product> results = new();
Create a while loop that will iterate until the
HasMoreResults
property of thefeed
variable returns false. This loop will ensure that you loop through all pages of server-side results.while (feed.HasMoreResults) { }
Within the while loop, asynchronously call the
ReadNextAsync
method of thefeed
variable and store the result in a variable namedresponse
.while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); }
Still within the while loop, use a foreach loop to go through each item in the response and add them to the
results
list.while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } }
Return the
results
list as the output of theRetrieveAllProductsAsync
method.return results;
Create a new asynchronous method named
RetrieveActiveProductsAsync
that returns anIEnumerable<Product>
.public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync() { }
For the next steps, add this code within the
RetrieveActiveProductsAsync
method.Create a new string named
sql
with a SQL query to retrieve multiple fields where a filter (@tagFilter
) is applied to tags array of each item.string sql = """ SELECT p.id, p.name, p.category, p.sku, p.description, p.price FROM products p JOIN tag IN p.tags WHERE STRINGEQUALS(tag, @tagFilter, true) """;
Create a new
QueryDefinition
variable namedquery
passing in thesql
string as the only query parameter. Also, use theWithParameter
fluid method to apply the valuered
to the@tagFilter
parameter.var query = new QueryDefinition( query: sql ) .WithParameter("@tagFilter", "red");
Use the
GetItemQueryIterator<>
generic method and thequery
variable to create an iterator that gets data from Azure Cosmos DB. Store the iterator in a variable namedfeed
. Wrap this entire expression in a using statement to dispose the iterator later.using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>( queryDefinition: query );
Use a while loop to iterate through multiple pages of results and store the value in a generic
List<>
named results. Return the results as the output of theRetrieveActiveProductsAsync
method.List<Product> results = new(); while (feed.HasMoreResults) { FeedResponse<Product> response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } } return results;
Save the Services/CosmosClient.cs file.
Tip
If you are unsure that your code is correct, you can check your source code against the sample code on GitHub.
Validate the final application
Finally, you'll run the application with hot reloads enabled. Running the application will validate that your code can access data from the API for NoSQL.
Back in the terminal, run the application.
dotnet run
The output of the run command should include a list of ports and URLs where the application is running. Open a new browser and navigate to the running web application. Observe all three pages of the running application. Each page should now include live data from Azure Cosmos DB.
Clean up resources
When no longer needed, delete the database used in this tutorial. To do so, navigate to the account page, select Data Explorer, select the cosmicworks
database, and then select Delete.
Next steps
Now that you've created your first .NET web application using Azure Cosmos DB, you can now dive deeper into the SDK to import more data, perform complex queries, and manage your Azure Cosmos DB for NoSQL resources.