Skip to main content
Version: v1.7 (stable)

How to configure ASP.NET Core apps to use Topaz

This guide shows you how to use the TheCloudTheory.Topaz.AspNetCore.Extensions NuGet package to provision local Azure infrastructure automatically at ASP.NET Core startup.

Installation

dotnet add package TheCloudTheory.Topaz.AspNetCore.Extensions

You will also need the Azure SDK packages that match the services you want to provision:

dotnet add package Azure.ResourceManager.KeyVault
dotnet add package Azure.ResourceManager.Storage
dotnet add package Azure.ResourceManager.ServiceBus
Order matters

Resources must be created before they are referenced. For example, a Key Vault must exist before you can write a secret into it, and a Storage Account must exist before its connection string can be stored as a Key Vault secret.

Builder API reference

MethodDescription
AddTopaz(subscriptionId, objectId)Entry point — returns a TopazEnvironmentBuilder
.AddSubscription(subscriptionId, name, credentials)Creates a subscription in Topaz
.AddResourceGroup(subscriptionId, name, location)Creates or updates a resource group
.AddStorageAccount(resourceGroup, name, content)Creates or updates a Storage Account
.AddKeyVault(resourceGroup, name, content)Creates or updates a Key Vault
.AddKeyVault(resourceGroup, name, content, secrets, objectId)Creates a Key Vault and populates it with secrets
.AddStorageAccountConnectionStringAsSecret(resourceGroup, storageAccount, keyVault, secretName, objectId)Reads the Storage Account key and stores the connection string as a Key Vault secret
.AddServiceBusNamespace(resourceGroup, namespace, data)Creates or updates a Service Bus namespace
.AddServiceBusQueue(resourceGroup, namespace, queueName, data)Creates or updates a queue inside a Service Bus namespace
.AddServiceBusTopic(resourceGroup, namespace, topicName, data)Creates or updates a topic inside a Service Bus namespace

The objectId parameter is the Entra ID object ID of the calling principal. Pass Guid.Empty.ToString() to act as a superadmin with no permission restrictions during local development.

Complete example

The following snippet shows a realistic startup that provisions a subscription, resource group, Storage Account, Key Vault with secrets, and stores the Storage Account connection string as a Key Vault secret:

using Azure.Core;
using Azure.ResourceManager.KeyVault.Models;
using Azure.ResourceManager.Storage.Models;
using Topaz.AspNetCore.Extensions;
using Topaz.Identity;

var builder = WebApplication.CreateBuilder(args);

var subscriptionId = Guid.Parse("00000000-0000-0000-0000-000000000001");
const string objectId = "00000000-0000-0000-0000-000000000000"; // superadmin
const string resourceGroupName = "rg-my-app";
const string storageAccountName = "stmyapp001";
const string keyVaultName = "kv-my-app";

await builder.Configuration
.AddTopaz(subscriptionId, objectId)
.AddSubscription(subscriptionId, "dev-local", new AzureLocalCredential(objectId))
.AddResourceGroup(subscriptionId, resourceGroupName, AzureLocation.WestEurope)
.AddStorageAccount(
resourceGroupName,
storageAccountName,
new StorageAccountCreateOrUpdateContent(
new StorageSku(StorageSkuName.StandardLrs),
StorageKind.StorageV2,
AzureLocation.WestEurope))
.AddKeyVault(
resourceGroupName,
keyVaultName,
new KeyVaultCreateOrUpdateContent(
AzureLocation.WestEurope,
new KeyVaultProperties(
Guid.Empty,
new KeyVaultSku(KeyVaultSkuFamily.A, KeyVaultSkuName.Standard))),
secrets: new Dictionary<string, string>
{
{ "my-app-setting", "hello-from-topaz" }
},
objectId: objectId)
.AddStorageAccountConnectionStringAsSecret(
resourceGroupName,
storageAccountName,
keyVaultName,
secretName: "connectionstring-storage",
objectId: objectId);

var app = builder.Build();
// ...
app.Run();

Running Topaz automatically with Testcontainers

To ensure the emulator is running without any manual steps — ideal for tests or dotnet run workflows — spin up the Topaz container before calling AddTopaz:

using DotNet.Testcontainers.Builders;

// Start Topaz before provisioning infrastructure
var topazContainer = await new ContainerBuilder()
.WithImage("thecloudtheory/topaz-cli:<tag>")
.WithPortBinding(8899) // ARM / Resource Manager
.WithPortBinding(8898) // Key Vault
.WithPortBinding(8891) // Blob Storage
.WithPortBinding(8890) // Table Storage
.WithPortBinding(8897) // Event Hub (HTTP)
.WithCommand("start", "--log-level", "Information")
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(8899))
.Build();

await topazContainer.StartAsync();

// Now provision infrastructure
await builder.Configuration
.AddTopaz(subscriptionId, objectId)
.AddSubscription(/* ... */);
Testcontainers NuGet package
dotnet add package Testcontainers

Service Bus example

using Azure.ResourceManager.ServiceBus.Models;
using Azure.ResourceManager.ServiceBus;

await builder.Configuration
.AddTopaz(subscriptionId, objectId)
.AddSubscription(subscriptionId, "dev-local", new AzureLocalCredential(objectId))
.AddResourceGroup(subscriptionId, "rg-messaging", AzureLocation.WestEurope)
.AddServiceBusNamespace(
"rg-messaging",
"sb-local",
new ServiceBusNamespaceData(AzureLocation.WestEurope)
{
Sku = new ServiceBusSku(ServiceBusSkuName.Standard)
})
.AddServiceBusQueue(
"rg-messaging",
"sb-local",
"orders",
new ServiceBusQueueData())
.AddServiceBusTopic(
"rg-messaging",
"sb-local",
"events",
new ServiceBusTopicData());
Star on GitHub