question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

WebJob: Setting CosmosDBTrigger connection string(s) at runtime

See original GitHub issue

I would like to be able to configure the CosmosDBTrigger connection string at runtime so that I can build the connection string dynamically, for example so I can use secrets stored in Key Vault.

Repro steps

I have the following method defined, using the CosmosDBTrigger:

public Task ProcessChangeFeed(
            [CosmosDBTrigger(
                databaseName: "mydatabase",
                collectionName: "mycollection",
                ConnectionStringSetting = "CosmosDB:ConnectionString",
                LeaseCollectionName = "leases",
                LeaseDatabaseName = "changefeed",
                LeaseConnectionStringSetting = "CosmosDB:ConnectionString",
                CreateLeaseCollectionIfNotExists = true)]
            IReadOnlyList<Document> documents,
            Microsoft.Extensions.Logging.ILogger logger)
        {

I’ve tried the following approaches to set the value of the setting CosmosDB:ConnectionString.

Hard-code the value in my appsettings.json file

This is the only approach that works but requires the full connection string, including the AccountKey to be in the config file, or in the Azure Portal (to avoid checking in secrets) - only really an option for local development.

[
  "CosmosDB":
  {
    "ConnectionString" : "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
  }
}

Using IPostConfigureOptions

This runs, but since the trigger doesn’t appear to use IOptions<CosmosDBOptions> it doesn’t help. I’m noting it here for completeness.

configurationBuilder.AddAzureKeyVault("https://mykeyvault.vault.azure.net/");
    public class PostConfigureCosmosDBOptions : IPostConfigureOptions<CosmosDBOptions>
    {
        private readonly IConfiguration configuration;

        public PostConfigureCosmosDBOptions(IConfiguration configuration)
        {
            this.configuration = configuration;
        }

        public void PostConfigure(string name, CosmosDBOptions cosmosDbOptions)
        {
            string cosmosDbAccountKey = this.configuration["CosmosDB:AccountKey"];

            string serviceEndpoint = this.configuration["CosmosDB:ServiceEndpoint"];

            string connectionString = $"AccountEndpoint={serviceEndpoint}‌​;AccountKey={cosmosDbAccountKey}";

            cosmosDbOptions.ConnectionString = connectionString;
        }
    }

Adding the setting that the trigger is looking for using AddInMemoryCollection

Again, this code runs and stepping through I can see it adding the correct value but the trigger doesn’t seem to use it.

string cosmosDbAccountKey = configurationRoot[KeyVaultSecretKeys.CosmosDbAuthKey];

string serviceEndpoint = configurationRoot[ConfigurationKeys.Data.CosmosDb.ServiceEndpoint];

string connectionString = $"AccountEndpoint={serviceEndpoint}‌​;AccountKey={cosmosDbAccountKey}";

configurationBuilder.AddInMemoryCollection(
    new Dictionary<string, string>
    {
        ["CosmosDB:ConnectionString"] = connectionString
    });

Error information

The error I get if the connection string isn’t configured is Request url is invalid which makes sense since it’s presumably null/empty.

System.InvalidOperationException: Cannot create Collection Information for Entity in database hrcm with lease leases in database changefeed : Request url is invalid.
ActivityId: 5d22add4-973b-4685-bee0-38b9c08f3e90, Microsoft.Azure.Documents.Common/2.0.0.0, Windows/10.0.17763 documentdb-netcore-sdk/2.1.3 ---> Microsoft.Azure.Documents.DocumentClientException: Request url is invalid.
ActivityId: 5d22add4-973b-4685-bee0-38b9c08f3e90, Microsoft.Azure.Documents.Common/2.0.0.0, Windows/10.0.17763 documentdb-netcore-sdk/2.1.3
   at Microsoft.Azure.Documents.Client.ClientExtensions.ParseResponseAsync(HttpResponseMessage responseMessage, JsonSerializerSettings serializerSettings)
   at Microsoft.Azure.Documents.Client.GatewayServiceConfigurationReader.GetDatabaseAccountAsync(Uri serviceEndpoint)
   at Microsoft.Azure.Documents.Routing.GlobalEndpointManager.GetDatabaseAccountFromAnyLocationsAsync(Uri defaultEndpoint, IList`1 locations, Func`2 getDatabaseAccountFn)
   at Microsoft.Azure.Documents.Client.GatewayServiceConfigurationReader.InitializeReaderAsync()
   at Microsoft.Azure.Documents.Client.DocumentClient.InitializeGatewayConfigurationReader()
   at Microsoft.Azure.Documents.Client.DocumentClient.GetInitializationTask()
   at Microsoft.Azure.Documents.Client.DocumentClient.EnsureValidClientAsync()
   at Microsoft.Azure.Documents.Client.DocumentClient.ReadDatabasePrivateAsync(String databaseLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance)
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.<>c__DisplayClass1_0.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.ExecuteRetryAsync(Func`1 callbackMethod, Func`3 callShouldRetry, Func`1 inBackoffAlternateCallbackMethod, TimeSpan minBackoffForInBackoffCallback, CancellationToken cancellationToken, Action`1 preRetryCallback)
   at Microsoft.Azure.Documents.ShouldRetryResult.ThrowIfDoneTrying(ExceptionDispatchInfo capturedException)
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.ExecuteRetryAsync(Func`1 callbackMethod, Func`3 callShouldRetry, Func`1 inBackoffAlternateCallbackMethod, TimeSpan minBackoffForInBackoffCallback, CancellationToken cancellationToken, Action`1 preRetryCallback)
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.ExecuteAsync(Func`1 callbackMethod, IRetryPolicy retryPolicy, CancellationToken cancellationToken, Action`1 preRetryCallback)
   at Microsoft.Azure.Documents.Client.DocumentClient.CreateDatabaseIfNotExistsPrivateAsync(Database database, RequestOptions options)
   at Microsoft.Azure.WebJobs.Extensions.CosmosDB.CosmosDBService.CreateDatabaseIfNotExistsAsync(Database database) in C:\azure-webjobs-sdk-extensions\src\WebJobs.Extensions.CosmosDB\Services\CosmosDBService.cs:line 48
   at Microsoft.Azure.WebJobs.Extensions.CosmosDB.CosmosDBUtility.CreateDatabaseAndCollectionIfNotExistAsync(ICosmosDBService service, String databaseName, String collectionName, String partitionKey, Int32 throughput) in C:\azure-webjobs-sdk-extensions\src\WebJobs.Extensions.CosmosDB\CosmosDBUtility.cs:line 41
   at Microsoft.Azure.WebJobs.Extensions.CosmosDB.CosmosDBTriggerAttributeBindingProvider.TryCreateAsync(TriggerBindingProviderContext context) in C:\azure-webjobs-sdk-extensions\src\WebJobs.Extensions.CosmosDB\Trigger\CosmosDBTriggerAttributeBindingProvider.cs:line 141
   --- End of inner exception stack trace ---
   at Microsoft.Azure.WebJobs.Extensions.CosmosDB.CosmosDBTriggerAttributeBindingProvider.TryCreateAsync(TriggerBindingProviderContext context) in C:\azure-webjobs-sdk-extensions\src\WebJobs.Extensions.CosmosDB\Trigger\CosmosDBTriggerAttributeBindingProvider.cs:line 146
   at Microsoft.Azure.WebJobs.Host.Triggers.CompositeTriggerBindingProvider.TryCreateAsync(TriggerBindingProviderContext context) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Triggers\CompositeTriggerBindingProvider.cs:line 22
   at Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexer.IndexMethodAsyncCore(MethodInfo method, IFunctionIndexCollector index, CancellationToken cancellationToken) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Indexers\FunctionIndexer.cs:line 190
   at Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexer.IndexMethodAsync(MethodInfo method, IFunctionIndexCollector index, CancellationToken cancellationToken) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Indexers\FunctionIndexer.cs:line 167

Expected behaviour

We use the ServiceBusTriggerAttribute and configure the connection string in an implementation of IPostConfigureOptions<ServiceBusOptions> and this works fine. The CosmosDBTrigger behaves differently and doesn’t appear to support this.

Related information

  • TargetFramework: netcoreapp2.1
  • Microsoft.Azure.WebJobs 3.0.1
  • Microsoft.Azure.WebJobs.Extensions.CosmosDB 3.0.1
  • Using generic HostBuilder in Program.Main()
  • Cosmos DB Emulator 2.0.0

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:1
  • Comments:9

github_iconTop GitHub Comments

1reaction
tjrobinsoncommented, Oct 31, 2018

Another approach, which also doesn’t seem to help:

[assembly: WebJobsStartup(typeof(Startup))]
namespace Empactis.CaseManager.AzureFunctions
{
    internal class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            builder.AddCosmosDB(
                options => options.ConnectionString = "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==");
        }
    }
}
0reactions
briandunningtoncommented, Jul 13, 2021

Here is how I did it using the PostConfigure options - note that you have to make sure the ConnectionStringSetting is set to "" or else the dynamically set value wont be used: https://briandunnington.github.io/azure_functions_dynamic_connection_string

Read more comments on GitHub >

github_iconTop Results From Across the Web

Set Cosmos DB Binding Connection String At Runtime
I am using Cosmos Db trigger azure function ,i want to get the ConnectionStringSetting value from key vault ,so i added below code...
Read more >
CosmosDBTrigger not getting invoked when CosmosDB ...
Based on your updated post, the issue is that the Functions runtime is not initializing your Function because of some configuration issue in ......
Read more >
Set Cosmos DB Trigger Connection String At Runtime
How to specify the trigger connection string at runtime and avoid storing secrets during local development.
Read more >
Set Azure WebJob Connection Strings with PowerShell
Here is a little snippet for quick provisionning for Azure Web App / Service settings for the usage of WebJobs.
Read more >
Azure web service - change database connection string at ...
Just have a couple connection strings in settings and program your application to switch between them as needed. As an option you can...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found