Working with CosmosClient in Azure Functions

Azure Functions allows you to inject an instance of the DocumentClient class to perform, read or write operations on your CosmosDB. This concept is known as input binding and there are multiple bindings available for various Azure resources (See Azure Functions triggers and bindings concepts). Unfortunately, there is no input binding for the new CosmosClient class that is part of the .NET SDK v3.

In this article, you will learn how you can use the new CosmosClient within your Azure Functions to leverage the Azure Cosmos DB .NET SDK v3.

Prerequisites

Create a local Functions project

We will use the Azure Functions Core Tools to scaffold the functions project directory.
In the terminal window or from a command prompt, run the following command to create the project:

 func init

After you run the command, you have to choose a runtime for the project. We choose dotnet:

Create a function

In addition, we have to create a function that we can invoke later. In this example, we create a dotnet core function with an HTTP trigger by running the following command:

func new --name "MyFunc" --template "HttpTrigger"

Install the Azure Cosmos DB package

In order to work with the CosmosClient, we have to install the Azure Cosmos DB client library. We can install it using the dotnet add package command:

dotnet add package Microsoft.Azure.Cosmos

Install the Azure Functions Extension package

The Microsoft.Azure.Functions.Extensions package enables us to use dependency injection within our Azure Functions. To install it, run the following command:

dotnet add package Microsoft.Azure.Functions.Extensions

Add the Startup class

Now it is time to add a Startup class where we can set up dependency injection for the CosmosClient. We register the service as a singleton and provide a factory method that retrieves the connection string from the application settings (line 22 – 32).

Note: Azure Functions uses the same service lifetimes as ASP.NET Dependency Injection. The singleton lifetime is recommended for connections like CosmosClient. It matches the host lifetime and is reused across function executions on that instance.

using System;
using azure_functions_cosmosclient;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(Startup))]

namespace azure_functions_cosmosclient
{
    public class Startup : FunctionsStartup
    {
        private static readonly IConfigurationRoot Configuration = new ConfigurationBuilder()
            .SetBasePath(Environment.CurrentDirectory)
            .AddJsonFile("appsettings.json", true)
            .AddEnvironmentVariables()
            .Build();

        public override void Configure(IFunctionsHostBuilder builder)
        {
           builder.Services.AddSingleton(s => {
                var connectionString = Configuration["CosmosDBConnection"];
                if (string.IsNullOrEmpty(connectionString))
                {
                    throw new InvalidOperationException(
                        "Please specify a valid CosmosDBConnection in the appSettings.json file or your Azure Functions Settings.");
                }

                return new CosmosClientBuilder(connectionString)
                    .Build();
           });
        }
    }
}

Set the CosmosDB connection string

In order for the above mentioned factory method to create the CosmosClient, we must first configure the connection string. Since we want to test the function locally, we can simply add the connection string to the file local.settings.json:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "CosmosDBConnection": "AccountEndpoint=...."
    }
}

Note: To maintain settings that are used by your Function App on Azure, see Configure function app settings.

Work with the CosmosClient

We will use Constructor injection to make the CosmosClient available in our function. The following sample demonstrates how the CosmosClient is injectioned into an HTTP-triggered function that simply creates a database with the name MyCosmosDb:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.Cosmos;

namespace azure_functions_cosmosclient
{
    public class MyFunc
    {
        private readonly CosmosClient _cosmosClient;

        public MyFunc(CosmosClient cosmosClient)
        {
            _cosmosClient = cosmosClient;
        }

        [FunctionName("MyFunc")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
        {
            await _cosmosClient.CreateDatabaseIfNotExistsAsync("MyCosmosDb");
            return new NoContentResult();
        }
    }
}

Note: The use of constructor injection requires that we don’t use static classes for our function classes. Also, the function itself must not be static, otherwise it cannot access member variables.

Test the function

To start the Functions project, simply run func start within your terminal and invoke the function using a GET request:

GET http://localhost:7071/api/MyFunc

After that, you will see the database MyCosmosDB within your ComosDB:

The whole source code is available on GitHub.