Use Azure Cosmos DB as an ASP.NET session state and caching provider

APPLIES TO: NoSQL

The Azure Cosmos DB session and cache provider allows you to use Azure Cosmos DB and apply its low latency and global scale capabilities for storing session state data and as a distributed cache within your application.

What is session state?

Session state is user data that tracks a user browsing through a web application during a period of time, within the same browser. The session state expires, and it's limited to the interactions a particular browser is having which doesn't extend across browsers. It's considered ephemeral data, if it isn't present it will not break the application. However, when it exists, it makes the experience faster for the user because the web application doesn't need to fetch it on every browser request for the same user.

It's often backed by some storage mechanism, that can in some cases, be external to the current web server and enable load-balancing requests of the same browser across multiple web servers to achieve higher scalability.

The simplest session state provider is the in-memory provider that only stores data on the local web server memory and requires the application to use Application Request Routing. This makes the browser session sticky to a particular web server (all requests for that browser need to always land on the same web server). The provider works well on simple scenarios but the stickiness requirement can bring load-balancing problems when web applications scale.

There are many external storage providers available, that can store the session data in a way that can be read and accessed by multiple web servers without requiring session stickiness and enable a higher scale.

Session state scenarios

Azure Cosmos DB can be used as a session state provider through the extension package Microsoft.Extensions.Caching.Cosmos uses the Azure Cosmos DB .NET SDK, using a Container as an effective session storage based on a key/value approach where the key is the session identifier.

Once the package is added, you can use AddCosmosCache as part of your Startup process (services.AddSession and app.UseSession are common initialization steps required for any session state provider):

public void ConfigureServices(IServiceCollection services)
{
  /* Other service configurations */
  services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
  {
      CosmosClientBuilder clientBuilder = new CosmosClientBuilder(
        "<nosql-account-endpoint>",
        tokenCredential
      )
        .WithApplicationRegion("West US");
      cacheOptions.ContainerName = "myContainer";
      cacheOptions.DatabaseName = "myDatabase";
      cacheOptions.ClientBuilder = clientBuilder;
      /* Creates the container if it does not exist */
      cacheOptions.CreateIfNotExists = true; 
  });

  services.AddSession(options =>
  {
      options.IdleTimeout = TimeSpan.FromSeconds(3600);
      options.Cookie.IsEssential = true;
  });
  /* Other service configurations */
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    /* Other configurations */

    app.UseSession();

    /* app.UseEndpoints and other configurations */
}

Where you specify the database and container you want the session state to be stored and optionally, create them if they don't exist using the CreateIfNotExists attribute.

Important

If you provide an existing container instead of using CreateIfNotExists, make sure it has time to live enabled.

You can customize your SDK client configuration by using the CosmosClientBuilder or if your application is already using a CosmosClient for other operations with Azure Cosmos DB, you can also inject it into the provider:

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = "myContainer";
    cacheOptions.DatabaseName = "myDatabase";
    cacheOptions.CosmosClient = preExistingClient;
    /* Creates the container if it does not exist */
    cacheOptions.CreateIfNotExists = true; 
});

After this, you can use ASP.NET Core sessions like with any other provider and use the HttpContext.Session object. Keep in mind to always try to load your session information asynchronously as per the ASP.NET recommendations.

Distributed cache scenarios

Given that the Azure Cosmos DB provider implements the IDistributedCache interface to act as a distributed cache provider, it can also be used for any application that requires distributed cache, not just for web applications that require a performant and distributed session state provider.

Distributed caches require data consistency to provide independent instances to be able to share that cached data. When using the Azure Cosmos DB provider, you can:

  • Use your Azure Cosmos DB account in Session consistency if you can enable Application Request Routing and make requests sticky to a particular instance.
  • Use your Azure Cosmos DB account in Bounded Staleness or Strong consistency without requiring request stickiness. This provides the greatest scale in terms of load distribution across your instances.

To use the Azure Cosmos DB provider as a distributed cache, it needs to be registered in ConfiguredServices with the services.AddCosmosCache call. Once that is done, any constructor in the application can ask for the cache by referencing IDistributedCache and it will receive the instance injected by dependency injection to be used:

public class MyBusinessClass
{
    private readonly IDistributedCache cache;

    public MyBusinessClass(IDistributedCache cache)
    {
        this.cache = cache;
    }
    
    public async Task SomeOperationAsync()
    {
        string someCachedValue = await this.cache.GetStringAsync("someKey");
        /* Use the cache */
    }
}

Troubleshooting and diagnosing

APPLIES TO: NoSQL

Since the Azure Cosmos DB provider uses the .NET SDK underneath, all the existing performance guidelines and troubleshooting guides apply to understanding any potential issue. Note, there is a distinct way to get access to the Diagnostics from the underlying Azure Cosmos DB operations because they cannot be exposed through the IDistributedCache APIs.

Registering the optional diagnostics delegate will allow you to capture and conditionally log any diagnostics to troubleshoot any cases like high latency:

void captureDiagnostics(CosmosDiagnostics diagnostics)
{
    if (diagnostics.GetClientElapsedTime() > SomePredefinedThresholdTime)
    {
        Console.WriteLine(diagnostics.ToString());
    }
}

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.DiagnosticsHandler = captureDiagnostics;
    /* other options */
});

Next steps

  • To find more details on the Azure Cosmos DB session and cache provider see the source code on GitHub.
  • Try out the Azure Cosmos DB session and cache provider by exploring a sample Explore an ASP.NET Core web application.
  • Read more about distributed caches in .NET.