In the previous post, you created custom read-only and read-write RBAC roles to work with Azure Cosmos DB for NoSQL. In this post, you will create a .NET Console app to load the data in the database.
Note: This series is a part of the Festive Tech Calendar, C# Advent Calendar, and .NET Advent Calendar. Be sure to check them out!
Set the COSMOS_URI environment variable
In this example and in our local web application, we will connect to the Cosmos database using the Cosmos URI. The ChainedTokenCredential will handle the credential part. To keep our URI out of source control, we are storing it in an environment variable. We are using the read-write URI so that we can load data in the database.
- Log into the Azure portal. Navigate to your Azure Cosmos DB resource.
- From the left hand navigation, under Settings, select Keys.
- Copy the value for URI.
- Create a new environment variable on your machine called COSMOS_URI with the value copied from Step 3.
Create the database and container
While the code could create the database and container, your account only has read-write access on the data plane. We did not assign access on the control plane. We will create the database and container ahead of running the application.
- In the Azure portal, while on your Azure Cosmos DB account, select Data Explorer.
- Once Azure Data Explorer loads, select New Container.
- For the database name, use HolidayCreatures. For the container name, use Creatures. For the partition key, use /id.
Create the app and add dependencies
First, create the console app:
dotnet new console
Once the project is created, then add references to two dependencies – the Azure Identity package and the Azure Cosmos SDK for .NET.
dotnet add package Azure.Identity --version=1.*
dotnet add package Microsoft.Azure.Cosmos
Download the sample data
The sample data is here: HolidayCreatures.csv.
Create a CosmosHelper class
To isolate some of the configuration, we are storing our Cosmos setup in a class called CosmosHelper.
- The database name, container name, and partition key are hard-coded in this example.
- The Cosmos URI is read from an environment variable. This is something you will set up on your machine locally as well as on the App Service when we deploy it to Azure. This allows us to set the value without committing it into source control.
- In the CosmosHelper constructor, note that the CosmosClient has a new that takes an endpoint and a token credential for its parameters. This constructor is supported in newer versions of the Azure Cosmos DB SDK – see the main post for those versions.
- We are using
ChainedTokenCredential
so that we can use one credential type in our development and another credential type in production. The order that they are listed matters – the ChainedTokenCredential will try each credential in the order listed and stops when it either gets a success or fails after exhausting all options in the chain. Learn more about ChainedTokenCredential.
Here is our code for CosmosHelper.cs:
using Azure.Identity;
using Microsoft.Azure.Cosmos;
public class CosmosHelper
{
CosmosClient client;
private static string CosmosUri => Environment.GetEnvironmentVariable("COSMOS_URI") ?? throw new ArgumentException("Missing env var: COSMOS_URI");
private static string DatabaseName = "HolidayCreatures";
private static string ContainerName = "Creatures";
private static string PartitionKey = "/id";
public CosmosHelper()
{
ChainedTokenCredential credential = new ChainedTokenCredential(new AzureCliCredential(),new ManagedIdentityCredential());
client = new(
accountEndpoint: CosmosUri,
tokenCredential: credential);
}
async public Task<Database> GetDatabase()
{
Database database = await client.CreateDatabaseIfNotExistsAsync(
id: DatabaseName
);
return database;
}
async public Task<Container> GetContainer()
{
Database database = await GetDatabase();
Container container = await database.CreateContainerIfNotExistsAsync(
id: ContainerName,
partitionKeyPath: PartitionKey,
throughput: 400
);
return container;
}
}
Create the Creature model
This is the model that we will use. Note that our id field is marked as a JSON property and that the id
field is case-sensitive.
using Newtonsoft.Json;
public class Creature {
[JsonProperty("id")]
public string CreatureId {get;set; } = Guid.NewGuid().ToString();
public string Name {get; set;} = "";
public string Description {get;set;} = "";
public bool IsNaughty { get;set; } = false;
public Creature() {
}
public Creature(string name, string description){
Name = name;
Description = description;
}
}
Update Program.cs
Now that the helper, model, and data are ready, update Program.cs. In Main, it will:
- Create a new CosmosHelper.
- Get the container.
- The script will create the database and container if they don’t exist. Be sure to run this application with an Azure account that has permissions to create databases and containers in your Azure Cosmos DB for NoSQL account.)
- Get the creatures.
- This function uses
TextFieldParser
to handle reading from the CSV.
- This function uses
- Write each creature to the Creatures container in the HolidayCreatures database in your Azure Cosmos DB for NoSQL account.
- This uses the upsert functionality.
- Creature IDs are going to be loaded with a counter rather than accepting the default of GUIDs.
Here is the code for Program.cs:
using Microsoft.Azure.Cosmos;
using Microsoft.VisualBasic.FileIO;
public class Program {
private static CosmosHelper cosmosHelper = new();
private static Container? container;
static void Main(string[] args){
cosmosHelper = new();
container = cosmosHelper.GetContainer().Result;
List<Creature> holidayCreatures = GetCreatures();
int creatureCounter = 1;
foreach(Creature creature in holidayCreatures){
creature.CreatureId = $"creature{creatureCounter}";
container.UpsertItemAsync(creature).Wait();
creatureCounter++;
}
}
private static List<Creature> GetCreatures(){
string pathToCsv = "HolidayCreatures.csv";
List<Creature> holidayCreatures = new List<Creature>();
using (TextFieldParser parser = new TextFieldParser(pathToCsv)){
parser.Delimiters = new string[] { ","};
while(!parser.EndOfData){
string[]? fields = parser.ReadFields();
if (fields != null){
if(fields[0]=="Name") continue;
Creature creature = new(name: fields[0], description: fields[1]);
creature.IsNaughty = Convert.ToBoolean(fields[2]);
holidayCreatures.Add(creature);
}
}
}
return holidayCreatures;
}
}
Run the program
Once all of these are in place, run this program with a user that has permission to create databases and containers in your Azure Cosmos DB for NoSQL account.
dotnet run
Confirm via Azure portal
You can check on the documents in the account by the following steps:
- Go to the Azure Cosmos DB for NoSQL account in the Azure portal.
- From the left navigation, select Data Explorer.
- In the Data section, expand HolidayCreatures, then expand Creatures. Select Items.
- When you select Items, it will pull all of the items for the container. You should see results that have id values like creature1, creature2, etc.
Now that there is data loaded in Azure Cosmos DB for NoSQL, let’s create a web app to pull the data out. We will take a passwordless approach in the next post.
[…] Create a .NET Console app to load the data […]
[…] Create a .NET Console app to load the data (Sarah Dutkiewicz) […]
[…] the previous post, we created a .NET console app to load data in Azure Cosmos DB for NoSQL. In this post, we are […]