From 04188a543f21b327b47dabd67e5c903b286b5bec Mon Sep 17 00:00:00 2001 From: Sidney Andrews Date: Tue, 8 Oct 2024 09:38:11 -0400 Subject: [PATCH 1/2] Revamp Oct 2024 --- azure.yaml | 4 +- infra/abbreviations.json | 4 +- infra/app/web.bicep | 22 +-------- infra/bicepconfig.json | 6 --- infra/core/database/cosmos-db/account.bicep | 17 ++++--- .../database/cosmos-db/nosql/account.bicep | 4 +- .../database/cosmos-db/nosql/container.bicep | 6 +-- .../database/cosmos-db/nosql/database.bicep | 4 +- .../cosmos-db/nosql/role/assignment.bicep | 9 ++-- .../cosmos-db/nosql/role/definition.bicep | 4 +- .../database/cosmos-db/table/account.bicep | 31 +++++++++++++ .../cosmos-db/table/role/assignment.bicep | 29 ++++++++++++ .../cosmos-db/table/role/definition.bicep | 37 +++++++++++++++ .../core/database/cosmos-db/table/table.bicep | 42 +++++++++++++++++ infra/main.bicep | 29 ++---------- src/web/Pages/Index.razor | 6 +-- src/web/Program.cs | 45 +++++-------------- .../{CosmosDbService.cs => DemoService.cs} | 15 ++----- 18 files changed, 192 insertions(+), 122 deletions(-) delete mode 100644 infra/bicepconfig.json create mode 100644 infra/core/database/cosmos-db/table/account.bicep create mode 100644 infra/core/database/cosmos-db/table/role/assignment.bicep create mode 100644 infra/core/database/cosmos-db/table/role/definition.bicep create mode 100644 infra/core/database/cosmos-db/table/table.bicep rename src/web/Services/{CosmosDbService.cs => DemoService.cs} (91%) diff --git a/azure.yaml b/azure.yaml index 8b7bfa4..e2b582a 100644 --- a/azure.yaml +++ b/azure.yaml @@ -15,7 +15,7 @@ hooks: postprovision: windows: run: | - dotnet user-secrets set "AZURE_COSMOS_DB_NOSQL_ENDPOINT" "$env:AZURE_COSMOS_ENDPOINT" --project ./src/web/Cosmos.Samples.NoSQL.Quickstart.Web.csproj + dotnet user-secrets set "AZURE_COSMOS_DB_NOSQL_ENDPOINT" "$env:AZURE_COSMOS_DB_NOSQL_ENDPOINT" --project ./src/web/Cosmos.Samples.NoSQL.Quickstart.Web.csproj Write-Host "" Write-Host "View the running web application in Azure Container Apps:" Write-Host "$env:AZURE_CONTAINER_APP_ENDPOINT" -ForegroundColor Cyan @@ -24,7 +24,7 @@ hooks: interactive: true posix: run: | - dotnet user-secrets set "AZURE_COSMOS_DB_NOSQL_ENDPOINT" "$AZURE_COSMOS_ENDPOINT" --project ./src/web/Cosmos.Samples.NoSQL.Quickstart.Web.csproj + dotnet user-secrets set "AZURE_COSMOS_DB_NOSQL_ENDPOINT" "$AZURE_COSMOS_DB_NOSQL_ENDPOINT" --project ./src/web/Cosmos.Samples.NoSQL.Quickstart.Web.csproj echo "" echo "View the running web application in Azure Container Apps:" echo -e "\033[0;36m$AZURE_CONTAINER_APP_ENDPOINT\033[0m" diff --git a/infra/abbreviations.json b/infra/abbreviations.json index 23031c4..d009e2c 100644 --- a/infra/abbreviations.json +++ b/infra/abbreviations.json @@ -2,7 +2,5 @@ "containerRegistry": "containerreg", "containerAppsEnv": "container-env", "containerAppsApp": "container-app", - "cosmosDbAccount": "cosmos-db-nosql", - "openAiAccount": "openai", - "userAssignedIdentity": "ua-id" + "cosmosDbAccount": "cosmos-db-nosql" } \ No newline at end of file diff --git a/infra/app/web.bicep b/infra/app/web.bicep index cd46e17..980a1db 100644 --- a/infra/app/web.bicep +++ b/infra/app/web.bicep @@ -9,14 +9,6 @@ param tags object = {} @description('Endpoint for Azure Cosmos DB for NoSQL account.') param databaseAccountEndpoint string -type managedIdentity = { - resourceId: string - clientId: string -} - -@description('Unique identifier for user-assigned managed identity.') -param userAssignedManagedIdentity managedIdentity - module containerAppsEnvironment '../core/host/container-apps/environments/managed.bicep' = { name: 'container-apps-env' params: { @@ -40,29 +32,19 @@ module containerAppsApp '../core/host/container-apps/app.bicep' = { name: 'azure-cosmos-db-nosql-endpoint' // Create a uniquely-named secret value: databaseAccountEndpoint // NoSQL database account endpoint } - { - name: 'azure-managed-identity-client-id' // Create a uniquely-named secret - value: userAssignedManagedIdentity.clientId // Client ID of user-assigned managed identity - } ] environmentVariables: [ { name: 'AZURE_COSMOS_DB_NOSQL_ENDPOINT' // Name of the environment variable referenced in the application secretRef: 'azure-cosmos-db-nosql-endpoint' // Reference to secret } - { - name: 'AZURE_MANAGED_IDENTITY_CLIENT_ID' - secretRef: 'azure-managed-identity-client-id' - } ] targetPort: 8080 - enableSystemAssignedManagedIdentity: false - userAssignedManagedIdentityIds: [ - userAssignedManagedIdentity.resourceId - ] + enableSystemAssignedManagedIdentity: true containerImage: 'mcr.microsoft.com/dotnet/samples:aspnetapp' } } output endpoint string = containerAppsApp.outputs.endpoint output envName string = containerAppsApp.outputs.name +output systemAssignedManagedIdentityPrincipalId string = containerAppsApp.outputs.systemAssignedManagedIdentityPrincipalId diff --git a/infra/bicepconfig.json b/infra/bicepconfig.json deleted file mode 100644 index 18227ea..0000000 --- a/infra/bicepconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "experimentalFeaturesEnabled": { - "resourceTypedParamsAndOutputs": true, - "userDefinedTypes": true - } -} \ No newline at end of file diff --git a/infra/core/database/cosmos-db/account.bicep b/infra/core/database/cosmos-db/account.bicep index 0cb9f1b..9a01506 100644 --- a/infra/core/database/cosmos-db/account.bicep +++ b/infra/core/database/cosmos-db/account.bicep @@ -14,7 +14,10 @@ param enableServerless bool = false @description('Disables key-based authentication. Defaults to false.') param disableKeyBasedAuth bool = false -resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { +@description('List of capabilities for the account. Defaults to an empty array.') +param capabilities object[] = [] + +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = { name: name location: location tags: tags @@ -37,11 +40,13 @@ resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { serverVersion: '4.2' } : {} disableLocalAuth: disableKeyBasedAuth - capabilities: (enableServerless) ? [ - { - name: 'EnableServerless' - } - ] : [] + capabilities: union(capabilities, + (enableServerless) ? [ + { + name: 'EnableServerless' + } + ] : [] + ) } } diff --git a/infra/core/database/cosmos-db/nosql/account.bicep b/infra/core/database/cosmos-db/nosql/account.bicep index 2f32fd0..998ed45 100644 --- a/infra/core/database/cosmos-db/nosql/account.bicep +++ b/infra/core/database/cosmos-db/nosql/account.bicep @@ -7,8 +7,8 @@ param tags object = {} @description('Enables serverless for this account. Defaults to false.') param enableServerless bool = false -@description('Disables key-based authentication. Defaults to false.') -param disableKeyBasedAuth bool = false +@description('Disables key-based authentication. Defaults to true.') +param disableKeyBasedAuth bool = true module account '../account.bicep' = { name: 'cosmos-db-nosql-account' diff --git a/infra/core/database/cosmos-db/nosql/container.bicep b/infra/core/database/cosmos-db/nosql/container.bicep index e72d28b..9544013 100644 --- a/infra/core/database/cosmos-db/nosql/container.bicep +++ b/infra/core/database/cosmos-db/nosql/container.bicep @@ -31,16 +31,16 @@ var options = setThroughput ? autoscale ? { throughput: throughput } : {} -resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = { +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { name: parentAccountName } -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2023-04-15' existing = { +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-05-15' existing = { name: parentDatabaseName parent: account } -resource container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-04-15' = { +resource container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = { name: name parent: database tags: tags diff --git a/infra/core/database/cosmos-db/nosql/database.bicep b/infra/core/database/cosmos-db/nosql/database.bicep index a1b98a9..36b67dc 100644 --- a/infra/core/database/cosmos-db/nosql/database.bicep +++ b/infra/core/database/cosmos-db/nosql/database.bicep @@ -23,11 +23,11 @@ var options = setThroughput ? autoscale ? { throughput: throughput } : {} -resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = { +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { name: parentAccountName } -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2023-04-15' = { +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-05-15' = { name: name parent: account tags: tags diff --git a/infra/core/database/cosmos-db/nosql/role/assignment.bicep b/infra/core/database/cosmos-db/nosql/role/assignment.bicep index 9a9d981..3e70217 100644 --- a/infra/core/database/cosmos-db/nosql/role/assignment.bicep +++ b/infra/core/database/cosmos-db/nosql/role/assignment.bicep @@ -9,17 +9,20 @@ param roleDefinitionId string @description('Id of the principal to assign the role definition for the account.') param principalId string -resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = { +@description('Scope of the role assignment. Defaults to the account.') +param scope string = '/' + +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { name: targetAccountName } -resource assignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-04-15' = { +resource assignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2024-05-15' = { name: guid(roleDefinitionId, principalId, account.id) parent: account properties: { principalId: principalId roleDefinitionId: roleDefinitionId - scope: account.id + scope: '${account.id}${scope}' } } diff --git a/infra/core/database/cosmos-db/nosql/role/definition.bicep b/infra/core/database/cosmos-db/nosql/role/definition.bicep index 770ceb4..ae220e6 100644 --- a/infra/core/database/cosmos-db/nosql/role/definition.bicep +++ b/infra/core/database/cosmos-db/nosql/role/definition.bicep @@ -12,11 +12,11 @@ param permissionsDataActions string[] = [] @description('An array of data actions that are denied. Defaults to an empty array.') param permissionsNonDataActions string[] = [] -resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = { +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { name: targetAccountName } -resource definition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2023-04-15' = { +resource definition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2024-05-15' = { name: guid('nosql-role-definition', account.id) parent: account properties: { diff --git a/infra/core/database/cosmos-db/table/account.bicep b/infra/core/database/cosmos-db/table/account.bicep new file mode 100644 index 0000000..e031083 --- /dev/null +++ b/infra/core/database/cosmos-db/table/account.bicep @@ -0,0 +1,31 @@ +metadata description = 'Create an Azure Cosmos DB for Table account.' + +param name string +param location string = resourceGroup().location +param tags object = {} + +@description('Enables serverless for this account. Defaults to false.') +param enableServerless bool = false + +@description('Disables key-based authentication. Defaults to true.') +param disableKeyBasedAuth bool = true + +module account '../account.bicep' = { + name: 'cosmos-db-table-account' + params: { + name: name + location: location + tags: tags + kind: 'GlobalDocumentDB' + enableServerless: enableServerless + disableKeyBasedAuth: disableKeyBasedAuth + capabilities: [ + { + name: 'EnableTable' + } + ] + } +} + +output endpoint string = account.outputs.endpoint +output name string = account.outputs.name diff --git a/infra/core/database/cosmos-db/table/role/assignment.bicep b/infra/core/database/cosmos-db/table/role/assignment.bicep new file mode 100644 index 0000000..ca6b9ca --- /dev/null +++ b/infra/core/database/cosmos-db/table/role/assignment.bicep @@ -0,0 +1,29 @@ +metadata description = 'Create an Azure Cosmos DB for Table role assignment.' + +@description('Name of the target Azure Cosmos DB account.') +param targetAccountName string + +@description('Id of the role definition to assign to the targeted principal and account.') +param roleDefinitionId string + +@description('Id of the principal to assign the role definition for the account.') +param principalId string + +@description('Scope of the role assignment. Defaults to the account.') +param scope string = '/' + +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { + name: targetAccountName +} + +resource assignment 'Microsoft.DocumentDB/databaseAccounts/tableRoleAssignments@2024-05-15' = { + name: guid(roleDefinitionId, principalId, account.id) + parent: account + properties: { + principalId: principalId + roleDefinitionId: roleDefinitionId + scope: '${account.id}${scope}' + } +} + +output id string = assignment.id diff --git a/infra/core/database/cosmos-db/table/role/definition.bicep b/infra/core/database/cosmos-db/table/role/definition.bicep new file mode 100644 index 0000000..362e954 --- /dev/null +++ b/infra/core/database/cosmos-db/table/role/definition.bicep @@ -0,0 +1,37 @@ +metadata description = 'Create an Azure Cosmos DB for Table role definition.' + +@description('Name of the target Azure Cosmos DB account.') +param targetAccountName string + +@description('Name of the role definiton.') +param definitionName string + +@description('An array of data actions that are allowed. Defaults to an empty array.') +param permissionsDataActions string[] = [] + +@description('An array of data actions that are denied. Defaults to an empty array.') +param permissionsNonDataActions string[] = [] + +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { + name: targetAccountName +} + +resource definition 'Microsoft.DocumentDB/databaseAccounts/tableRoleDefinitions@2024-05-15' = { + name: guid('table-role-definition', account.id) + parent: account + properties: { + assignableScopes: [ + account.id + ] + permissions: [ + { + dataActions: permissionsDataActions + notDataActions: permissionsNonDataActions + } + ] + roleName: definitionName + type: 'CustomRole' + } +} + +output id string = definition.id diff --git a/infra/core/database/cosmos-db/table/table.bicep b/infra/core/database/cosmos-db/table/table.bicep new file mode 100644 index 0000000..df23234 --- /dev/null +++ b/infra/core/database/cosmos-db/table/table.bicep @@ -0,0 +1,42 @@ +metadata description = 'Create an Azure Cosmos DB for Table table.' + +param name string +param tags object = {} + +@description('Name of the parent Azure Cosmos DB account.') +param parentAccountName string + +@description('Enables throughput setting at this resource level. Defaults to false.') +param setThroughput bool = false + +@description('Enables autoscale. If setThroughput is enabled, defaults to false.') +param autoscale bool = false + +@description('The amount of throughput set. If setThroughput is enabled, defaults to 400.') +param throughput int = 400 + +var options = setThroughput ? autoscale ? { + autoscaleSettings: { + maxThroughput: throughput + } +} : { + throughput: throughput +} : {} + +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' existing = { + name: parentAccountName +} + +resource table 'Microsoft.DocumentDB/databaseAccounts/tables@2024-05-15' = { + name: name + parent: account + tags: tags + properties: { + options: options + resource: { + id: name + } + } +} + +output name string = table.name diff --git a/infra/main.bicep b/infra/main.bicep index be5de79..8632867 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -17,7 +17,6 @@ param cosmosDbAccountName string = '' param containerRegistryName string = '' param containerAppsEnvName string = '' param containerAppsAppName string = '' -param userAssignedIdentityName string = '' // serviceName is used as value for the tag (azd-service-name) azd uses to identify deployment host param serviceName string = 'web' @@ -35,16 +34,6 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { tags: tags } -module identity 'app/identity.bicep' = { - name: 'identity' - scope: resourceGroup - params: { - identityName: !empty(userAssignedIdentityName) ? userAssignedIdentityName : '${abbreviations.userAssignedIdentity}-${resourceToken}' - location: location - tags: tags - } -} - module database 'app/database.bicep' = { name: 'database' scope: resourceGroup @@ -81,10 +70,6 @@ module web 'app/web.bicep' = { envName: !empty(containerAppsEnvName) ? containerAppsEnvName : '${abbreviations.containerAppsEnv}-${resourceToken}' appName: !empty(containerAppsAppName) ? containerAppsAppName : '${abbreviations.containerAppsApp}-${resourceToken}' databaseAccountEndpoint: database.outputs.endpoint - userAssignedManagedIdentity: { - resourceId: identity.outputs.resourceId - clientId: identity.outputs.clientId - } location: location tags: tags serviceTag: serviceName @@ -96,15 +81,15 @@ module security 'app/security.bicep' = { scope: resourceGroup params: { databaseAccountName: database.outputs.accountName - appPrincipalId: identity.outputs.principalId + appPrincipalId: web.outputs.systemAssignedManagedIdentityPrincipalId userPrincipalId: !empty(principalId) ? principalId : null } } // Database outputs -output AZURE_COSMOS_ENDPOINT string = database.outputs.endpoint -output AZURE_COSMOS_DATABASE_NAME string = data.outputs.database.name -output AZURE_COSMOS_CONTAINER_NAMES array = map(data.outputs.containers, c => c.name) +output AZURE_COSMOS_DB_NOSQL_ENDPOINT string = database.outputs.endpoint +output AZURE_COSMOS_DB_NOSQL_DATABASE_NAME string = data.outputs.database.name +output AZURE_COSMOS_DB_NOSQL_CONTAINER_NAMES array = map(data.outputs.containers, c => c.name) // Container outputs output AZURE_CONTAINER_REGISTRY_ENDPOINT string = registry.outputs.endpoint @@ -114,11 +99,5 @@ output AZURE_CONTAINER_REGISTRY_NAME string = registry.outputs.name output AZURE_CONTAINER_APP_ENDPOINT string = web.outputs.endpoint output AZURE_CONTAINER_ENVIRONMENT_NAME string = web.outputs.envName -// Identity outputs -output AZURE_USER_ASSIGNED_IDENTITY_NAME string = identity.outputs.name - // Security outputs output AZURE_NOSQL_ROLE_DEFINITION_ID string = security.outputs.roleDefinitions.nosql - -// Application environment variables -output AZURE_COSMOS_DB_NOSQL_ENDPOINT string = database.outputs.endpoint diff --git a/src/web/Pages/Index.razor b/src/web/Pages/Index.razor index 05ab653..c0c487c 100644 --- a/src/web/Pages/Index.razor +++ b/src/web/Pages/Index.razor @@ -1,5 +1,5 @@ @page "/" -@inject ICosmosDbService cosmosDbService +@inject IDemoService demoService @using System.Text
@@ -34,7 +34,7 @@
         
             ENDPOINT:
         
-        @cosmosDbService.GetEndpoint()
+        @demoService.GetEndpoint()
     
 
 
@@ -54,7 +54,7 @@
 
         await WriteToConsoleAync("Current Status:\tStarting...");
 
-        await cosmosDbService.RunDemoAsync(writeOutputAync: WriteToConsoleAync);
+        await demoService.RunAsync(writeOutputAync: WriteToConsoleAync);
 
         await WriteToConsoleAync("Current Status:\tStopping...");
         await SetRunAgain(true);
diff --git a/src/web/Program.cs b/src/web/Program.cs
index b395f4e..a57a4f1 100644
--- a/src/web/Program.cs
+++ b/src/web/Program.cs
@@ -5,41 +5,18 @@
 builder.Services.AddRazorPages();
 builder.Services.AddServerSideBlazor();
 
-// 
-if (builder.Environment.IsDevelopment())
+builder.Services.AddSingleton((_) =>
 {
-    builder.Services.AddSingleton((_) =>
-    {
-        //     
-        CosmosClient client = new(
-            accountEndpoint: builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!,
-            tokenCredential: new DefaultAzureCredential()
-        );
-        //     
-        return client;
-    });
-}
-else
-{
-    builder.Services.AddSingleton((_) =>
-    {
-        // 
-        CosmosClient client = new(
-            accountEndpoint: builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!,
-            tokenCredential: new DefaultAzureCredential(
-                new DefaultAzureCredentialOptions()
-                {
-                    ManagedIdentityClientId = builder.Configuration["AZURE_MANAGED_IDENTITY_CLIENT_ID"]!
-                }
-            )
-        );
-        // 
-        return client;
-    });
-}
-// 
-
-builder.Services.AddTransient();
+    // 
+    CosmosClient client = new(
+        accountEndpoint: builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!,
+        tokenCredential: new DefaultAzureCredential()
+    );
+    // 
+    return client;
+});
+
+builder.Services.AddTransient();
 
 var app = builder.Build();
 
diff --git a/src/web/Services/CosmosDbService.cs b/src/web/Services/DemoService.cs
similarity index 91%
rename from src/web/Services/CosmosDbService.cs
rename to src/web/Services/DemoService.cs
index e0a5771..633e20e 100644
--- a/src/web/Services/CosmosDbService.cs
+++ b/src/web/Services/DemoService.cs
@@ -1,25 +1,18 @@
 using Cosmos.Samples.NoSQL.Quickstart.Web.Models;
 using Microsoft.Azure.Cosmos;
 
-internal interface ICosmosDbService
+internal interface IDemoService
 {
-    Task RunDemoAsync(Func writeOutputAync);
+    Task RunAsync(Func writeOutputAync);
 
     string GetEndpoint();
 }
 
-internal sealed class CosmosDbService : ICosmosDbService
+internal sealed class DemoService(CosmosClient client) : IDemoService
 {
-    private readonly CosmosClient client;
-
-    public CosmosDbService(CosmosClient client)
-    {
-        this.client = client;
-    }
-
     public string GetEndpoint() => $"{client.Endpoint}";
 
-    public async Task RunDemoAsync(Func writeOutputAync)
+    public async Task RunAsync(Func writeOutputAync)
     {
         // 
         Database database = client.GetDatabase("cosmicworks");

From 362c2f18b436ce7f528d5deb01353a09853024c4 Mon Sep 17 00:00:00 2001
From: Sidney Andrews 
Date: Tue, 8 Oct 2024 10:03:03 -0400
Subject: [PATCH 2/2] Remove .NET package reference

---
 src/web/_Imports.razor | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/web/_Imports.razor b/src/web/_Imports.razor
index 361219f..de88dc0 100644
--- a/src/web/_Imports.razor
+++ b/src/web/_Imports.razor
@@ -1,6 +1,5 @@
 @using Microsoft.AspNetCore.Components.Routing
 @using Microsoft.AspNetCore.Components.Web
-@using Microsoft.Azure.Cosmos
 @using Microsoft.JSInterop
 @using Cosmos.Samples.NoSQL.Quickstart.Web
 @using Cosmos.Samples.NoSQL.Quickstart.Web.Models