Skip to content

Deploy and scale an Orleans app on Azure

In this quickstart, you deploy and scale an Orleans URL shortener app on Azure Container Apps. The app allows users to submit a full URL to the app, which returns a shortened version they can share with others to direct them to the original site. Orleans and Azure provide the scalability features necessary to host high traffic apps like URL shorteners. Orleans is also compatible with any other hosting service that supports .NET.

At the end of this quickstart, you have a scalable app running in Azure to provide URL shortener functionality. Along the way you learn to:

  • Pull an Azure Developer CLI template
  • Deploy an Orleans app to Azure
  • Scale the app to multiple instances

The sample application is available as an Azure Developer CLI template. Through this quickstart: you pull the template application, deploy the template and sample code to Azure, change the template to implement your preferred persistence grain, deploy the necessary resources, and then deploy the final application.

  1. Open a terminal in an empty directory.

  2. Authenticate to the Azure Developer CLI using azd auth login. Follow the steps specified by the tool to authenticate to the CLI using your preferred Azure credentials.

    Terminal window
    azd auth login
  3. Get the sample application using the AZD template orleans-url-shortener and the azd init command.

    Terminal window
    azd init --template orleans-url-shortener
  4. During initialization, configure a unique environment name.

  5. Deploy the Azure Cosmos DB for NoSQL account using azd up. The Bicep templates also deploy a sample web application.

    Terminal window
    azd up
  6. During the provisioning process, select your subscription and desired location. Wait for the provisioning and deployment process to complete. The process can take approximately five minutes.

  7. Once the provisioning of your Azure resources is done, a URL to the running web application is included in the output.

    Deploying services (azd deploy)
    (✓) Done: Deploying service web
    - Endpoint: <https://[container-app-sub-domain].azurecontainerapps.io>
    SUCCESS: Your application was provisioned and deployed to Azure in 5 minutes 0 seconds.
  8. Use the URL in the console to navigate to your web application in the browser.

    Screenshot of the running URL shortener web application.

  9. In the browser address bar, test the shorten endpoint by adding a URL path such as /shorten?url=https://www.microsoft.com. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.

    {
    "original": "https://www.microsoft.com",
    "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>"
    }
  10. Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.

The original deployment only deployed the minimal services necessary to host the URL shortener app. To use an Azure data service for grain persistence, you must first configure the template to deploy your preferred service.

Applies to: Azure Storage

  1. Using the terminal, run azd env set to configure the DEPLOY_AZURE_TABLE_STORAGE environment variable to enable deployment of Azure Table Storage.

    Terminal window
    azd env set DEPLOY_AZURE_TABLE_STORAGE true

Applies to: Azure Cosmos DB for NoSQL

  1. Using the terminal, run azd env set to configure the DEPLOY_AZURE_COSMOS_DB_NOSQL environment variable to enable deployment of Azure Cosmos DB for NoSQL.

    Terminal window
    azd env set DEPLOY_AZURE_COSMOS_DB_NOSQL true
  1. Run azd provision to redeploy your application architecture with the new configuration. Wait for the provisioning process to complete. The process can take approximately two minutes.

    Terminal window
    azd provision

Before adding shared providers, align the template with the maintained snippets:

  1. Change the working directory to ./src/web/.

    Terminal window
    cd ./src/web
  2. In the project file, change TargetFramework to net10.0.

  3. In ./src/web/Dockerfile, update both .NET container images: use mcr.microsoft.com/dotnet/sdk:10.0 for the build stage and mcr.microsoft.com/dotnet/aspnet:10.0 for the runtime stage.

  4. Upgrade the Orleans host package:

    Terminal window
    dotnet package add Microsoft.Orleans.Server --version 10.2.2

Next, install the corresponding Microsoft.Orleans.Clustering.* and Microsoft.Orleans.Persistence.* NuGet packages. These services use role-based access control for passwordless authentication, so you must also import the Azure.Identity NuGet package.

Applies to: Azure Storage

  1. Import the Azure.Identity package from NuGet:

    Terminal window
    dotnet package add Azure.Identity
  2. Import the Microsoft.Orleans.Clustering.AzureStorage and Microsoft.Orleans.Persistence.AzureStorage packages.

    FeatureNuGet package
    ClusteringMicrosoft.Orleans.Clustering.AzureStorage
    PersistenceMicrosoft.Orleans.Persistence.AzureStorage
    Terminal window
    dotnet package add Microsoft.Orleans.Clustering.AzureStorage --version 10.2.2
    dotnet package add Microsoft.Orleans.Persistence.AzureStorage --version 10.2.2

Applies to: Azure Cosmos DB for NoSQL

  1. Import the Azure.Identity package from NuGet:

    Terminal window
    dotnet package add Azure.Identity
  2. Import the Microsoft.Orleans.Clustering.Cosmos and Microsoft.Orleans.Persistence.Cosmos packages.

    FeatureNuGet package
    ClusteringMicrosoft.Orleans.Clustering.Cosmos
    PersistenceMicrosoft.Orleans.Persistence.Cosmos
    Terminal window
    dotnet package add Microsoft.Orleans.Clustering.Cosmos --version 10.2.2
    dotnet package add Microsoft.Orleans.Persistence.Cosmos --version 10.2.2

The sample app initially creates a localhost cluster and persists grain state in memory. When hosted in Azure, Orleans can use a shared data service for cluster membership and durable grain state.

  1. Find and remove the existing builder configuration code in the src/web/Program.cs file.

    builder.Host.UseOrleans(static siloBuilder =>
    {
    siloBuilder.UseLocalhostClustering();
    siloBuilder.AddMemoryGrainStorage("urls");
    });

Applies to: Azure Storage

  1. Add the required using directives:

    using Azure.Data.Tables;
    using Azure.Identity;
    using Orleans.Configuration;
  2. Replace the builder configuration with the example here, which implements these key concepts:

    if (builder.Environment.IsDevelopment())
    {
    builder.Host.UseOrleans(static siloBuilder =>
    {
    siloBuilder
    .UseLocalhostClustering()
    .AddMemoryGrainStorage("urls");
    });
    }
    else
    {
    builder.Host.UseOrleans(siloBuilder =>
    {
    var endpoint = new Uri(builder.Configuration["AZURE_TABLE_STORAGE_ENDPOINT"]!);
    var credential = new DefaultAzureCredential();
    siloBuilder
    .UseAzureStorageClustering(options =>
    {
    options.TableServiceClient = new TableServiceClient(endpoint, credential);
    })
    .AddAzureTableGrainStorage(name: "urls", options =>
    {
    options.TableServiceClient = new TableServiceClient(endpoint, credential);
    })
    .Configure<ClusterOptions>(options =>
    {
    options.ClusterId = "url-shortener";
    options.ServiceId = "urls";
    });
    });
    }

Applies to: Azure Cosmos DB for NoSQL

  1. Add the required using directives:

    using Azure.Identity;
    using Orleans.Configuration;
  2. Replace the builder configuration with the example here, which implements these key concepts:

    • A conditional environment check is added to ensure the app runs properly in both local development and Azure hosted scenarios.
    • HostingExtensions.UseCosmosClustering configures the Orleans cluster to use Azure Cosmos DB for NoSQL and authenticates using DefaultAzureCredential.
    • The configuration assigns ClusterId and ServiceId.
    • ClusterId identifies a cluster so its clients and silos can communicate. Use a different value for deployments that must remain isolated.
    • ServiceId identifies the application and should remain consistent across deployments.
    if (builder.Environment.IsDevelopment())
    {
    builder.Host.UseOrleans(static siloBuilder =>
    {
    siloBuilder
    .UseLocalhostClustering()
    .AddMemoryGrainStorage("urls");
    });
    }
    else
    {
    builder.Host.UseOrleans(siloBuilder =>
    {
    var endpoint = builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!;
    var credential = new DefaultAzureCredential();
    siloBuilder
    .UseCosmosClustering(options =>
    {
    options.ConfigureCosmosClient(endpoint, credential);
    })
    .AddCosmosGrainStorage(name: "urls", options =>
    {
    options.ConfigureCosmosClient(endpoint, credential);
    })
    .Configure<ClusterOptions>(options =>
    {
    options.ClusterId = "url-shortener";
    options.ServiceId = "urls";
    });
    });
    }
  1. Run azd deploy to redeploy your application code as a Docker container. Wait for the deployment process to complete. The process can take approximately one minute.

    Terminal window
    azd deploy

Validate that your updated code works by using the deployed application again and checking to see where it stores data.

  1. In the browser address bar, test the shorten endpoint again by adding a URL path such as /shorten?url=https://learn.microsoft.com/dotnet/orleans. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.

    {
    "original": "https://learn.microsoft.com/dotnet/orleans",
    "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>"
    }
  2. Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.

Optionally, you can verify that the cluster and state data is stored as expected in the storage account you created.

  1. In the Azure portal, navigate to the resource group that was deployed in this quickstart.

Applies to: Azure Storage

  1. Navigate to the overview page of the Azure Storage account.

  2. Within the navigation, select Storage browser.

  3. Expand the Tables navigation item to discover two tables created by Orleans:

    • OrleansGrainState: This table stores the persistent state grain data used by the application to handle the URL redirects.
    • OrleansSiloInstances: This table tracks essential silo data for the Orleans cluster.
  4. Select the OrleansGrainState table. The table holds a row entry for every URL redirect persisted by the app during your testing.

    A screenshot showing Orleans data in Azure Table Storage.

Applies to: Azure Cosmos DB for NoSQL

  1. Navigate to the overview page of the Azure Cosmos DB for NoSQL account.

  2. Within the navigation, select Data Explorer.

  3. Observe the following containers you created earlier in this guide:

    • OrleansStorage: This table stores the persistent state grain data used by the application to handle the URL redirects.

    • OrleansCluster: This table tracks essential silo data for the Orleans cluster.

Don’t increase the replica count of the single silo Container App created by this quickstart. Orleans requires every silo to advertise a unique, directly reachable endpoint pair, while Azure Container Apps doesn’t provide stable per-replica addresses for one app.

To scale this topology, deploy additional one-replica silo apps with distinct advertised endpoints. See Deploy Orleans to Azure Container Apps for the supported topology, networking requirements, and upgrade procedure.

Applies to: Azure Storage

Applies to: Azure Cosmos DB for NoSQL