Set up Azure Data Explorer in the AppHost
This article is the reference for the Aspire Azure Data Explorer (Kusto) hosting integration. It enumerates the AppHost APIs — with examples for both AppHost.cs and apphost.ts — that you use to model Azure Data Explorer clusters and databases in your AppHost project.
Azure Data Explorer (also known as Kusto) is a fast and highly scalable data exploration service for log and telemetry data. The hosting integration models the following types:
AzureKustoClusterResource: A top-level cluster resource that holds databases and carries connection information.AzureKustoReadWriteDatabaseResource: A read-write database within a cluster.AzureKustoEmulatorResource: The local Kustainer emulator running as a container.
Installation
Section titled “Installation”To start building an Aspire app that uses Azure Data Explorer, install the 📦 Aspire.Hosting.Azure.Kusto NuGet package:
aspire add azure-kustoLearn more about aspire add in the command reference.
Or, choose a manual installation approach:
#:package Aspire.Hosting.Azure.Kusto@*<PackageReference Include="Aspire.Hosting.Azure.Kusto" Version="*" />aspire add azure-kustoLearn more about aspire add in the command reference.
This updates your aspire.config.json with the Azure Data Explorer hosting integration package:
{ "packages": { "Aspire.Hosting.Azure.Kusto": "13.3.0-preview.1.26256.5" }}Add an Azure Data Explorer cluster resource
Section titled “Add an Azure Data Explorer cluster resource”Once you’ve installed the hosting integration, call AddAzureKustoCluster (or addAzureKustoCluster) to declare a cluster, then call AddReadWriteDatabase (or addReadWriteDatabase) to declare one or more databases inside it:
var builder = DistributedApplication.CreateBuilder(args);
var kusto = builder.AddAzureKustoCluster("kusto");var database = kusto.AddReadWriteDatabase("analytics");
builder.AddProject<Projects.ExampleProject>() .WithReference(database) .WaitFor(database);
// After adding all resources, run the app...import { createBuilder } from './.modules/aspire.js';
const builder = await createBuilder();
const kusto = await builder.addAzureKustoCluster("kusto");const database = await kusto.addReadWriteDatabase("analytics");
await builder.addNodeApp("api", "./api", "index.js") .withReference(database) .waitFor(database);
// After adding all resources, run the app...The preceding code adds an Azure Data Explorer cluster named kusto with a read-write database named analytics. The WithReference (or withReference) method injects the connection information into the consuming project.
Run as emulator
Section titled “Run as emulator”The hosting integration supports running Azure Data Explorer locally using the Kustainer container image. This lets you develop and test without an Azure subscription or an existing cluster.
var builder = DistributedApplication.CreateBuilder(args);
var kusto = builder.AddAzureKustoCluster("kusto") .RunAsEmulator();
var database = kusto.AddReadWriteDatabase("analytics");
builder.AddProject<Projects.ExampleProject>() .WithReference(database) .WaitFor(database);
// After adding all resources, run the app...import { createBuilder } from './.modules/aspire.js';
const builder = await createBuilder();
const kusto = await builder.addAzureKustoCluster("kusto") .runAsEmulator();
const database = await kusto.addReadWriteDatabase("analytics");
await builder.addNodeApp("api", "./api", "index.js") .withReference(database) .waitFor(database);
// After adding all resources, run the app...When running as an emulator, databases are automatically created when the container starts and the connection string is configured automatically for local development.
Configure the emulator host port
Section titled “Configure the emulator host port”By default, the emulator uses a dynamic host port. To fix the host port, pass a configureContainer callback and call WithHostPort (or withHostPort):
var builder = DistributedApplication.CreateBuilder(args);
var kusto = builder.AddAzureKustoCluster("kusto") .RunAsEmulator(emulator => { emulator.WithHostPort(8080); });
// After adding all resources, run the app...import { createBuilder } from './.modules/aspire.js';
const builder = await createBuilder();
const kusto = await builder.addAzureKustoCluster("kusto") .runAsEmulator({ configureContainer: async (emulator) => { await emulator.withHostPort({ port: 8080 }); }, });
// After adding all resources, run the app...Add a database creation script
Section titled “Add a database creation script”When running as an emulator, you can provide a KQL script to initialize the database with tables and data:
var builder = DistributedApplication.CreateBuilder(args);
var kusto = builder.AddAzureKustoCluster("kusto") .RunAsEmulator();
var database = kusto.AddReadWriteDatabase("analytics") .WithCreationScript(""" .create table Events ( Timestamp: datetime, EventType: string, Message: string ) """);
builder.AddProject<Projects.ExampleProject>() .WithReference(database) .WaitFor(database);
// After adding all resources, run the app...The TypeScript AppHost doesn’t currently expose withCreationScript on the database resource. To initialise the emulator database schema from a TypeScript AppHost, apply schema through your application on startup instead.
Provisioning-generated Bicep
Section titled “Provisioning-generated Bicep”If you’re new to Bicep, it’s a domain-specific language for defining Azure resources. With Aspire, you don’t need to write Bicep by hand — the provisioning APIs generate it for you. When you publish your app, the generated Bicep is written alongside the manifest file. When you add an Azure Data Explorer resource, the following Bicep is generated:
@description('The location for the resource(s) to be deployed.')param location string = resourceGroup().location
param principalId string
param principalName string
resource kusto 'Microsoft.Kusto/clusters@2024-04-13' = { name: take('kusto${uniqueString(resourceGroup().id)}', 22) location: location sku: { name: 'Dev(No SLA)_Standard_E2a_v4' tier: 'Basic' capacity: 1 } properties: { enableAutoStop: true } tags: { 'aspire-resource-name': 'kusto' }}
resource analytics 'Microsoft.Kusto/clusters/databases@2024-04-13' = { name: 'analytics' location: location kind: 'ReadWrite' parent: kusto}
resource kusto_principalAssignment 'Microsoft.Kusto/clusters/principalAssignments@2024-04-13' = { name: guid(kusto.id, principalId, 'AllDatabasesAdmin') properties: { principalId: principalId principalType: 'App' role: 'AllDatabasesAdmin' } parent: kusto}
output kustoClusterUri string = kusto.properties.uriThe preceding Bicep provisions an Azure Data Explorer cluster with a dev/test SKU and a read-write database.
The generated Bicep is a starting point — customise it through the C# provisioning APIs, not by editing the file directly, as direct edits are overwritten on the next publish.
Customize provisioning infrastructure
Section titled “Customize provisioning infrastructure”All Aspire Azure resources subclass AzureProvisioningResource. The ConfigureInfrastructure (or configureInfrastructure) API lets you customise the generated Bicep with a fluent callback:
var builder = DistributedApplication.CreateBuilder(args);
var kusto = builder.AddAzureKustoCluster("kusto") .ConfigureInfrastructure(infra => { var cluster = infra.GetProvisionableResources() .OfType<KustoCluster>() .Single();
cluster.Sku = new KustoSku { Name = KustoSkuName.StandardE8aV4, Tier = KustoSkuTier.Standard, Capacity = 2 }; cluster.IsAutoStopEnabled = false; cluster.Tags.Add("environment", "production"); });
kusto.AddReadWriteDatabase("analytics");import { createBuilder } from './.modules/aspire.js';
const builder = await createBuilder();
const kusto = await builder.addAzureKustoCluster("kusto");await kusto.configureInfrastructure(async (infra) => { // Modify infra resources here using the AzureResourceInfrastructure API});
await kusto.addReadWriteDatabase("analytics");
// After adding all resources, run the app...The preceding C# code:
- Retrieves the
KustoClusterfrom the provisionable resources. - Sets the SKU to
StandardE8aV4with a capacity of2. - Disables auto-stop.
- Adds a tag with key
environmentand valueproduction.
For more configuration options, see Azure.Provisioning customization. For the full list of configurable properties, see the Azure.Provisioning.Kusto API documentation.
Connection properties
Section titled “Connection properties”When you add an Azure Data Explorer resource to your application, the connection properties are made available to consuming resources:
Cluster resource
Section titled “Cluster resource”| Property | Description |
|---|---|
Uri | The URI of the Azure Data Explorer cluster endpoint. |
Database resource
Section titled “Database resource”| Property | Description |
|---|---|
Uri | The URI of the parent cluster endpoint (inherited from cluster). |
DatabaseName | The name of the database. |
The connection string format is: Data Source=https://{cluster-uri};Initial Catalog={database-name}
Hosting integration health checks
Section titled “Hosting integration health checks”The Azure Data Explorer hosting integration automatically adds health checks for both cluster and database resources. The health check verifies that the cluster is reachable and responding to queries, and that any referenced database exists and is accessible.
Health check status is displayed in the Aspire dashboard resource list.