From 391e91059199f0f9e56b743208710dc061202f28 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 22 May 2024 16:45:04 -0700 Subject: [PATCH 1/9] Expose CosmosClientOptions --- .../src/Config/CosmosDBBindingOptions.cs | 25 +++++++++---------- .../src/Config/CosmosDBBindingOptionsSetup.cs | 6 ++++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index 8a2eb9e1b..1b1187888 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -21,6 +21,8 @@ internal class CosmosDBBindingOptions public CosmosSerializer? Serializer { get; set; } + public CosmosClientOptions? CosmosClientOptions { get; set; } + internal string BuildCacheKey(string connection, string region) => $"{connection}|{region}"; internal ConcurrentDictionary ClientCache { get; } = new ConcurrentDictionary(); @@ -34,29 +36,26 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") string cacheKey = BuildCacheKey(ConnectionName!, preferredLocations); - CosmosClientOptions cosmosClientOptions = new () - { - ConnectionMode = ConnectionMode.Gateway - }; - - if (!string.IsNullOrEmpty(preferredLocations)) + // Do not override if preferred locations is configured via CosmosClientOptions + if (!string.IsNullOrEmpty(preferredLocations) && CosmosClientOptions.ApplicationPreferredRegions is null) { - cosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); + CosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); } - if (Serializer is not null) + // Do not override if the serializer is configured via CosmosClientOptions + if (Serializer is not null && CosmosClientOptions.Serializer is null) { - cosmosClientOptions.Serializer = Serializer; + CosmosClientOptions.Serializer = Serializer; } - return ClientCache.GetOrAdd(cacheKey, (c) => CreateService(cosmosClientOptions)); + return ClientCache.GetOrAdd(cacheKey, (c) => CreateService()); } - private CosmosClient CreateService(CosmosClientOptions cosmosClientOptions) + private CosmosClient CreateService() { return string.IsNullOrEmpty(ConnectionString) - ? new CosmosClient(AccountEndpoint, Credential, cosmosClientOptions) // AAD auth - : new CosmosClient(ConnectionString, cosmosClientOptions); // Connection string based auth + ? new CosmosClient(AccountEndpoint, Credential, CosmosClientOptions) // AAD auth + : new CosmosClient(ConnectionString, CosmosClientOptions); // Connection string based auth } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs index 294efb3ad..84379da9e 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using Microsoft.Azure.Cosmos; using Microsoft.Azure.Functions.Worker.Extensions; using Microsoft.Azure.Functions.Worker.Extensions.CosmosDB; using Microsoft.Extensions.Azure; @@ -15,12 +16,14 @@ internal class CosmosDBBindingOptionsSetup : IConfigureNamedOptions _workerOptions; + private readonly IOptionsMonitor _cosmosClientOptions; - public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions) + public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosClientOptions) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _componentFactory = componentFactory ?? throw new ArgumentNullException(nameof(componentFactory)); _workerOptions = workerOptions ?? throw new ArgumentNullException(nameof(workerOptions)); + _cosmosClientOptions = cosmosClientOptions ?? throw new ArgumentNullException(nameof(cosmosClientOptions)); } public void Configure(CosmosDBBindingOptions options) @@ -57,6 +60,7 @@ public void Configure(string connectionName, CosmosDBBindingOptions options) } options.Serializer = new WorkerCosmosSerializer(_workerOptions.CurrentValue.Serializer); + options.CosmosClientOptions = _cosmosClientOptions.CurrentValue; } } } \ No newline at end of file From 505712a953b40f756b671ec18d2305e9fe6db811 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 22 May 2024 16:45:16 -0700 Subject: [PATCH 2/9] Update release notes and extension version --- .../release_notes.md | 27 ++++++++++++++++--- .../src/Worker.Extensions.CosmosDB.csproj | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/release_notes.md b/extensions/Worker.Extensions.CosmosDB/release_notes.md index 4514dbf4b..df5f6f6c1 100644 --- a/extensions/Worker.Extensions.CosmosDB/release_notes.md +++ b/extensions/Worker.Extensions.CosmosDB/release_notes.md @@ -4,8 +4,27 @@ - My change description (#PR/#issue) --> -### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 4.8.1 +### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 5.0.0 -- Updating `Microsoft.Azure.WebJobs.Extensions.CosmosDB` reference to 4.6.1 -- Updating `Microsoft.Extensions.Azure` reference to 1.7.3 -- Updating `Microsoft.Azure.Cosmos` reference to 3.39.1 +- Expose `CosmosClientOptions` to allow configuration of the CosmosDB client (#2483) + +#### Breaking Change + +- **Default `ConnectionMode` Change:** The default `ConnectionMode` for `CosmosClientOptions` has been changed from `Gateway` to `Direct`. + This change is due to `Direct` being the default value for `ConnectionMode` in the Cosmos SDK; now that we are exposing those options, + it is not possible for us to tell whether the user has explicitly set the connection mode to `Direct` or not, so we must default to the + SDK's default value + +##### How to Maintain Previous Behavior + +To continue using `Gateway` mode, configure the `CosmosClientOptions` in your `Program` class as shown below: + +```csharp +.ConfigureFunctionsWorkerDefaults((builder) => +{ + builder.Services.Configure((options) => + { + options.ConnectionMode = ConnectionMode.Gateway; + }); +}) +``` diff --git a/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj b/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj index 0835d2793..c735c315b 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj +++ b/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj @@ -6,7 +6,7 @@ Azure Cosmos DB extensions for .NET isolated functions - 4.8.1 + 5.0.0 false From 30126e1e7aa57d912cda3209cd9f16f25f3ae106 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 5 Jun 2024 14:40:53 -0700 Subject: [PATCH 3/9] Implement CosmosDBOptions --- .../release_notes.md | 6 ++--- .../src/Config/CosmosDBBindingOptions.cs | 25 +++++++++++++------ .../src/Config/CosmosDBBindingOptionsSetup.cs | 8 +++--- .../src/Config/CosmosDBOptions.cs | 15 +++++++++++ ...tionsWorkerApplicationBuilderExtensions.cs | 14 +++++++++++ 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs diff --git a/extensions/Worker.Extensions.CosmosDB/release_notes.md b/extensions/Worker.Extensions.CosmosDB/release_notes.md index df5f6f6c1..ca98abfb5 100644 --- a/extensions/Worker.Extensions.CosmosDB/release_notes.md +++ b/extensions/Worker.Extensions.CosmosDB/release_notes.md @@ -6,7 +6,7 @@ ### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 5.0.0 -- Expose `CosmosClientOptions` to allow configuration of the CosmosDB client (#2483) +- Implement `CosmosDBOptions` to allow configuration of the CosmosDB service client via `CosmosClientOptions` (#2483) #### Breaking Change @@ -22,9 +22,9 @@ To continue using `Gateway` mode, configure the `CosmosClientOptions` in your `P ```csharp .ConfigureFunctionsWorkerDefaults((builder) => { - builder.Services.Configure((options) => + builder.ConfigureCosmosDBExtensionOptions((options) => { - options.ConnectionMode = ConnectionMode.Gateway; + options.ClientOptions.ConnectionMode = ConnectionMode.Gateway; }); }) ``` diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index 1b1187888..b5a141f38 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -9,6 +9,12 @@ namespace Microsoft.Azure.Functions.Worker { + /// + /// Internal options for configuring the CosmosDB binding. + /// This class is used internally by the Azure Functions runtime to manage the CosmosDB connection and clients. + /// It is not intended to be used directly in user code. + /// Any public configuration options should be set on the class, which is publicly accessible. + /// internal class CosmosDBBindingOptions { public string? ConnectionName { get; set; } @@ -21,7 +27,7 @@ internal class CosmosDBBindingOptions public CosmosSerializer? Serializer { get; set; } - public CosmosClientOptions? CosmosClientOptions { get; set; } + public CosmosDBOptions? CosmosDBOptions { get; set; } internal string BuildCacheKey(string connection, string region) => $"{connection}|{region}"; @@ -34,18 +40,23 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") throw new ArgumentNullException(nameof(ConnectionName)); } + if (CosmosDBOptions is null) + { + CosmosDBOptions = new CosmosDBOptions(); + } + string cacheKey = BuildCacheKey(ConnectionName!, preferredLocations); // Do not override if preferred locations is configured via CosmosClientOptions - if (!string.IsNullOrEmpty(preferredLocations) && CosmosClientOptions.ApplicationPreferredRegions is null) + if (!string.IsNullOrEmpty(preferredLocations) && CosmosDBOptions.ClientOptions.ApplicationPreferredRegions is null) { - CosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); + CosmosDBOptions.ClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); } // Do not override if the serializer is configured via CosmosClientOptions - if (Serializer is not null && CosmosClientOptions.Serializer is null) + if (Serializer is not null && CosmosDBOptions.ClientOptions.Serializer is null) { - CosmosClientOptions.Serializer = Serializer; + CosmosDBOptions.ClientOptions.Serializer = Serializer; } return ClientCache.GetOrAdd(cacheKey, (c) => CreateService()); @@ -54,8 +65,8 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") private CosmosClient CreateService() { return string.IsNullOrEmpty(ConnectionString) - ? new CosmosClient(AccountEndpoint, Credential, CosmosClientOptions) // AAD auth - : new CosmosClient(ConnectionString, CosmosClientOptions); // Connection string based auth + ? new CosmosClient(AccountEndpoint, Credential, CosmosDBOptions?.ClientOptions) // AAD auth + : new CosmosClient(ConnectionString, CosmosDBOptions?.ClientOptions); // Connection string based auth } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs index 84379da9e..4f0b5e05d 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs @@ -16,14 +16,14 @@ internal class CosmosDBBindingOptionsSetup : IConfigureNamedOptions _workerOptions; - private readonly IOptionsMonitor _cosmosClientOptions; + private readonly IOptionsMonitor _cosmosDBOptions; - public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosClientOptions) + public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosClientOptions) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _componentFactory = componentFactory ?? throw new ArgumentNullException(nameof(componentFactory)); _workerOptions = workerOptions ?? throw new ArgumentNullException(nameof(workerOptions)); - _cosmosClientOptions = cosmosClientOptions ?? throw new ArgumentNullException(nameof(cosmosClientOptions)); + _cosmosDBOptions = cosmosClientOptions ?? throw new ArgumentNullException(nameof(cosmosClientOptions)); } public void Configure(CosmosDBBindingOptions options) @@ -60,7 +60,7 @@ public void Configure(string connectionName, CosmosDBBindingOptions options) } options.Serializer = new WorkerCosmosSerializer(_workerOptions.CurrentValue.Serializer); - options.CosmosClientOptions = _cosmosClientOptions.CurrentValue; + options.CosmosDBOptions = _cosmosDBOptions.CurrentValue; } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs new file mode 100644 index 000000000..3e27f5d64 --- /dev/null +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using Microsoft.Azure.Cosmos; + +namespace Microsoft.Azure.Functions.Worker +{ + public class CosmosDBOptions + { + /// + /// Gets or sets the CosmosClientOptions. + /// + public CosmosClientOptions ClientOptions { get; set; } = new CosmosClientOptions(); + } +} \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs index fc904ef25..124333b82 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; +using Microsoft.Azure.Cosmos; using Microsoft.Extensions.Azure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -31,5 +33,17 @@ public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtension(this return builder; } + + /// + /// Configures the CosmosDBOptions for the Functions Worker Cosmos extension. + /// + /// The IFunctionsWorkerApplicationBuilder to add the configuration to. + /// An Action to configure the CosmosDBOptions. + /// The same instance of the for chaining. + public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtensionOptions(this IFunctionsWorkerApplicationBuilder builder, Action options) + { + builder.Services.Configure(options); + return builder; + } } } From 0b1fc5c5adb01dfaa0a6af2df6dde049dc5f1581 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 5 Jun 2024 14:42:20 -0700 Subject: [PATCH 4/9] Rename param --- .../src/Config/CosmosDBBindingOptionsSetup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs index 4f0b5e05d..b9861ac28 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs @@ -18,12 +18,12 @@ internal class CosmosDBBindingOptionsSetup : IConfigureNamedOptions _workerOptions; private readonly IOptionsMonitor _cosmosDBOptions; - public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosClientOptions) + public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosOptions) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _componentFactory = componentFactory ?? throw new ArgumentNullException(nameof(componentFactory)); _workerOptions = workerOptions ?? throw new ArgumentNullException(nameof(workerOptions)); - _cosmosDBOptions = cosmosClientOptions ?? throw new ArgumentNullException(nameof(cosmosClientOptions)); + _cosmosDBOptions = cosmosOptions ?? throw new ArgumentNullException(nameof(cosmosOptions)); } public void Configure(CosmosDBBindingOptions options) From 2919d35e31ceba93cdc5f974b02669f50c841d82 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 5 Jun 2024 16:51:02 -0700 Subject: [PATCH 5/9] Rename to CosmosDBExtensionOptions --- .../release_notes.md | 2 +- .../src/Config/CosmosDBBindingOptions.cs | 20 +++++++++---------- .../src/Config/CosmosDBBindingOptionsSetup.cs | 8 ++++---- ...Options.cs => CosmosDBExtensionOptions.cs} | 2 +- ...tionsWorkerApplicationBuilderExtensions.cs | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) rename extensions/Worker.Extensions.CosmosDB/src/Config/{CosmosDBOptions.cs => CosmosDBExtensionOptions.cs} (91%) diff --git a/extensions/Worker.Extensions.CosmosDB/release_notes.md b/extensions/Worker.Extensions.CosmosDB/release_notes.md index ca98abfb5..0971b3730 100644 --- a/extensions/Worker.Extensions.CosmosDB/release_notes.md +++ b/extensions/Worker.Extensions.CosmosDB/release_notes.md @@ -6,7 +6,7 @@ ### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 5.0.0 -- Implement `CosmosDBOptions` to allow configuration of the CosmosDB service client via `CosmosClientOptions` (#2483) +- Implement `CosmosDBExtensionOptions` to allow configuration of the CosmosDB service client via `CosmosClientOptions` (#2483) #### Breaking Change diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index b5a141f38..66ec079ee 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -13,7 +13,7 @@ namespace Microsoft.Azure.Functions.Worker /// Internal options for configuring the CosmosDB binding. /// This class is used internally by the Azure Functions runtime to manage the CosmosDB connection and clients. /// It is not intended to be used directly in user code. - /// Any public configuration options should be set on the class, which is publicly accessible. + /// Any public configuration options should be set on the class, which is publicly accessible. /// internal class CosmosDBBindingOptions { @@ -27,7 +27,7 @@ internal class CosmosDBBindingOptions public CosmosSerializer? Serializer { get; set; } - public CosmosDBOptions? CosmosDBOptions { get; set; } + public CosmosDBExtensionOptions? CosmosExtensionOptions { get; set; } internal string BuildCacheKey(string connection, string region) => $"{connection}|{region}"; @@ -40,23 +40,23 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") throw new ArgumentNullException(nameof(ConnectionName)); } - if (CosmosDBOptions is null) + if (CosmosExtensionOptions is null) { - CosmosDBOptions = new CosmosDBOptions(); + CosmosExtensionOptions = new CosmosExtensionOptions(); } string cacheKey = BuildCacheKey(ConnectionName!, preferredLocations); // Do not override if preferred locations is configured via CosmosClientOptions - if (!string.IsNullOrEmpty(preferredLocations) && CosmosDBOptions.ClientOptions.ApplicationPreferredRegions is null) + if (!string.IsNullOrEmpty(preferredLocations) && CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions is null) { - CosmosDBOptions.ClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); + CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); } // Do not override if the serializer is configured via CosmosClientOptions - if (Serializer is not null && CosmosDBOptions.ClientOptions.Serializer is null) + if (Serializer is not null && CosmosExtensionOptions.ClientOptions.Serializer is null) { - CosmosDBOptions.ClientOptions.Serializer = Serializer; + CosmosExtensionOptions.ClientOptions.Serializer = Serializer; } return ClientCache.GetOrAdd(cacheKey, (c) => CreateService()); @@ -65,8 +65,8 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") private CosmosClient CreateService() { return string.IsNullOrEmpty(ConnectionString) - ? new CosmosClient(AccountEndpoint, Credential, CosmosDBOptions?.ClientOptions) // AAD auth - : new CosmosClient(ConnectionString, CosmosDBOptions?.ClientOptions); // Connection string based auth + ? new CosmosClient(AccountEndpoint, Credential, CosmosExtensionOptions?.ClientOptions) // AAD auth + : new CosmosClient(ConnectionString, CosmosExtensionOptions?.ClientOptions); // Connection string based auth } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs index b9861ac28..ba2a320d7 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs @@ -16,14 +16,14 @@ internal class CosmosDBBindingOptionsSetup : IConfigureNamedOptions _workerOptions; - private readonly IOptionsMonitor _cosmosDBOptions; + private readonly IOptionsMonitor _cosmosExtensionOptions; - public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosOptions) + public CosmosDBBindingOptionsSetup(IConfiguration configuration, AzureComponentFactory componentFactory, IOptionsMonitor workerOptions, IOptionsMonitor cosmosExtensionOptions) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _componentFactory = componentFactory ?? throw new ArgumentNullException(nameof(componentFactory)); _workerOptions = workerOptions ?? throw new ArgumentNullException(nameof(workerOptions)); - _cosmosDBOptions = cosmosOptions ?? throw new ArgumentNullException(nameof(cosmosOptions)); + _cosmosExtensionOptions = cosmosExtensionOptions ?? throw new ArgumentNullException(nameof(cosmosExtensionOptions)); } public void Configure(CosmosDBBindingOptions options) @@ -60,7 +60,7 @@ public void Configure(string connectionName, CosmosDBBindingOptions options) } options.Serializer = new WorkerCosmosSerializer(_workerOptions.CurrentValue.Serializer); - options.CosmosDBOptions = _cosmosDBOptions.CurrentValue; + options.CosmosExtensionOptions = _cosmosExtensionOptions.CurrentValue; } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs similarity index 91% rename from extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs rename to extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs index 3e27f5d64..2d43f1ef0 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs @@ -5,7 +5,7 @@ namespace Microsoft.Azure.Functions.Worker { - public class CosmosDBOptions + public class CosmosDBExtensionOptions { /// /// Gets or sets the CosmosClientOptions. diff --git a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs index 124333b82..5f1c2adc8 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs @@ -35,12 +35,12 @@ public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtension(this } /// - /// Configures the CosmosDBOptions for the Functions Worker Cosmos extension. + /// Configures the CosmosDBExtensionOptions for the Functions Worker Cosmos extension. /// /// The IFunctionsWorkerApplicationBuilder to add the configuration to. - /// An Action to configure the CosmosDBOptions. + /// An Action to configure the CosmosDBExtensionOptions. /// The same instance of the for chaining. - public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtensionOptions(this IFunctionsWorkerApplicationBuilder builder, Action options) + public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtensionOptions(this IFunctionsWorkerApplicationBuilder builder, Action options) { builder.Services.Configure(options); return builder; From 3d1c33c8e70d39d7f69db9738d5ff798db27cd50 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Thu, 6 Jun 2024 10:46:21 -0700 Subject: [PATCH 6/9] Add default connection mode --- .../Worker.Extensions.CosmosDB/release_notes.md | 16 ++++------------ .../src/Config/CosmosDBBindingOptions.cs | 2 +- .../src/Config/CosmosDBExtensionOptions.cs | 2 +- .../src/Worker.Extensions.CosmosDB.csproj | 2 +- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/release_notes.md b/extensions/Worker.Extensions.CosmosDB/release_notes.md index 0971b3730..a0bdf4810 100644 --- a/extensions/Worker.Extensions.CosmosDB/release_notes.md +++ b/extensions/Worker.Extensions.CosmosDB/release_notes.md @@ -4,27 +4,19 @@ - My change description (#PR/#issue) --> -### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 5.0.0 +### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 4.9.0 - Implement `CosmosDBExtensionOptions` to allow configuration of the CosmosDB service client via `CosmosClientOptions` (#2483) -#### Breaking Change - -- **Default `ConnectionMode` Change:** The default `ConnectionMode` for `CosmosClientOptions` has been changed from `Gateway` to `Direct`. - This change is due to `Direct` being the default value for `ConnectionMode` in the Cosmos SDK; now that we are exposing those options, - it is not possible for us to tell whether the user has explicitly set the connection mode to `Direct` or not, so we must default to the - SDK's default value - -##### How to Maintain Previous Behavior - -To continue using `Gateway` mode, configure the `CosmosClientOptions` in your `Program` class as shown below: +#### Example Usage ```csharp .ConfigureFunctionsWorkerDefaults((builder) => { builder.ConfigureCosmosDBExtensionOptions((options) => { - options.ClientOptions.ConnectionMode = ConnectionMode.Gateway; + options.ClientOptions.ConnectionMode = ConnectionMode.Direct; + options.ClientOptions.ApplicationName = "MyApp"; }); }) ``` diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index 66ec079ee..d431ba908 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -42,7 +42,7 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") if (CosmosExtensionOptions is null) { - CosmosExtensionOptions = new CosmosExtensionOptions(); + CosmosExtensionOptions = new CosmosDBExtensionOptions(); } string cacheKey = BuildCacheKey(ConnectionName!, preferredLocations); diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs index 2d43f1ef0..d2a9509cd 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs @@ -10,6 +10,6 @@ public class CosmosDBExtensionOptions /// /// Gets or sets the CosmosClientOptions. /// - public CosmosClientOptions ClientOptions { get; set; } = new CosmosClientOptions(); + public CosmosClientOptions ClientOptions { get; set; } = new() { ConnectionMode = ConnectionMode.Gateway }; } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj b/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj index c735c315b..d374523d9 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj +++ b/extensions/Worker.Extensions.CosmosDB/src/Worker.Extensions.CosmosDB.csproj @@ -6,7 +6,7 @@ Azure Cosmos DB extensions for .NET isolated functions - 5.0.0 + 4.9.0 false From 9505e037074436af98f151134771d08dc9b79fbc Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Mon, 10 Jun 2024 14:01:06 -0700 Subject: [PATCH 7/9] Move serializer to extension opts pipeline --- .../src/Config/CosmosDBBindingOptions.cs | 23 ++++++++----------- .../src/Config/CosmosDBBindingOptionsSetup.cs | 3 +-- ...tionsWorkerApplicationBuilderExtensions.cs | 3 +++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index d431ba908..35aef28f0 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -25,8 +25,6 @@ internal class CosmosDBBindingOptions public TokenCredential? Credential { get; set; } - public CosmosSerializer? Serializer { get; set; } - public CosmosDBExtensionOptions? CosmosExtensionOptions { get; set; } internal string BuildCacheKey(string connection, string region) => $"{connection}|{region}"; @@ -50,23 +48,20 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") // Do not override if preferred locations is configured via CosmosClientOptions if (!string.IsNullOrEmpty(preferredLocations) && CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions is null) { - CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); - } - - // Do not override if the serializer is configured via CosmosClientOptions - if (Serializer is not null && CosmosExtensionOptions.ClientOptions.Serializer is null) - { - CosmosExtensionOptions.ClientOptions.Serializer = Serializer; + // Copy to avoid modifying the original options + var cosmosClientOptions = CosmosExtensionOptions.ClientOptions; + cosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); + return ClientCache.GetOrAdd(cacheKey, (c) => CreateService(cosmosClientOptions)); } - return ClientCache.GetOrAdd(cacheKey, (c) => CreateService()); + return ClientCache.GetOrAdd(cacheKey, (c) => CreateService(CosmosExtensionOptions.ClientOptions)); } - private CosmosClient CreateService() + private CosmosClient CreateService(CosmosClientOptions cosmosClientOptions) { return string.IsNullOrEmpty(ConnectionString) - ? new CosmosClient(AccountEndpoint, Credential, CosmosExtensionOptions?.ClientOptions) // AAD auth - : new CosmosClient(ConnectionString, CosmosExtensionOptions?.ClientOptions); // Connection string based auth + ? new CosmosClient(AccountEndpoint, Credential, cosmosClientOptions) // AAD auth + : new CosmosClient(ConnectionString, cosmosClientOptions); // Connection string based auth } } -} \ No newline at end of file +} diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs index ba2a320d7..4a154bddc 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptionsSetup.cs @@ -59,8 +59,7 @@ public void Configure(string connectionName, CosmosDBBindingOptions options) options.Credential = _componentFactory.CreateTokenCredential(connectionSection); } - options.Serializer = new WorkerCosmosSerializer(_workerOptions.CurrentValue.Serializer); options.CosmosExtensionOptions = _cosmosExtensionOptions.CurrentValue; } } -} \ No newline at end of file +} diff --git a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs index 5f1c2adc8..50fbf030d 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs @@ -29,6 +29,9 @@ public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtension(this builder.Services.AddAzureClientsCore(); // Adds AzureComponentFactory builder.Services.AddOptions(); + builder.Services.AddOptions() + .Configure>((cosmos, worker) => cosmos.ClientOptions.Serializer = new WorkerCosmosSerializer(worker.Value.Serializer)); + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, CosmosDBBindingOptionsSetup>()); return builder; From 7f13d14fbfcd256dbecc8e374ec18731c28219cb Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Tue, 11 Jun 2024 15:41:19 -0700 Subject: [PATCH 8/9] Add clone and null check --- .../src/Config/CosmosDBBindingOptions.cs | 4 ++-- .../src/Config/CosmosDBExtensionOptions.cs | 5 +++++ .../FunctionsWorkerApplicationBuilderExtensions.cs | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index 35aef28f0..9ec4f6366 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -48,8 +48,8 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") // Do not override if preferred locations is configured via CosmosClientOptions if (!string.IsNullOrEmpty(preferredLocations) && CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions is null) { - // Copy to avoid modifying the original options - var cosmosClientOptions = CosmosExtensionOptions.ClientOptions; + // Clone to avoid modifying the original options + var cosmosClientOptions = CosmosExtensionOptions.Clone().ClientOptions; cosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); return ClientCache.GetOrAdd(cacheKey, (c) => CreateService(cosmosClientOptions)); } diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs index d2a9509cd..fbd608148 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs @@ -11,5 +11,10 @@ public class CosmosDBExtensionOptions /// Gets or sets the CosmosClientOptions. /// public CosmosClientOptions ClientOptions { get; set; } = new() { ConnectionMode = ConnectionMode.Gateway }; + + internal CosmosDBExtensionOptions Clone() + { + return (CosmosDBExtensionOptions)this.MemberwiseClone(); + } } } \ No newline at end of file diff --git a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs index 50fbf030d..dc8743bbd 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Extensions/FunctionsWorkerApplicationBuilderExtensions.cs @@ -30,7 +30,13 @@ public static IFunctionsWorkerApplicationBuilder ConfigureCosmosDBExtension(this builder.Services.AddAzureClientsCore(); // Adds AzureComponentFactory builder.Services.AddOptions(); builder.Services.AddOptions() - .Configure>((cosmos, worker) => cosmos.ClientOptions.Serializer = new WorkerCosmosSerializer(worker.Value.Serializer)); + .Configure>((cosmos, worker) => + { + if (cosmos.ClientOptions.Serializer is null) + { + cosmos.ClientOptions.Serializer = new WorkerCosmosSerializer(worker.Value.Serializer); + } + }); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, CosmosDBBindingOptionsSetup>()); From 656bd30199fea183e76d5f58eb7047fccc017090 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Wed, 12 Jun 2024 11:48:36 -0700 Subject: [PATCH 9/9] Add clone extension --- .../src/Config/CosmosDBBindingOptions.cs | 2 +- .../src/Config/CosmosDBExtensionOptions.cs | 7 +--- .../src/Extensions/CloningExtensions.cs | 34 +++++++++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 extensions/Worker.Extensions.CosmosDB/src/Extensions/CloningExtensions.cs diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs index 9ec4f6366..403ee836a 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBBindingOptions.cs @@ -49,7 +49,7 @@ internal virtual CosmosClient GetClient(string preferredLocations = "") if (!string.IsNullOrEmpty(preferredLocations) && CosmosExtensionOptions.ClientOptions.ApplicationPreferredRegions is null) { // Clone to avoid modifying the original options - var cosmosClientOptions = CosmosExtensionOptions.Clone().ClientOptions; + CosmosClientOptions cosmosClientOptions = CosmosExtensionOptions.ClientOptions.MemberwiseClone(); cosmosClientOptions.ApplicationPreferredRegions = Utilities.ParsePreferredLocations(preferredLocations); return ClientCache.GetOrAdd(cacheKey, (c) => CreateService(cosmosClientOptions)); } diff --git a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs index fbd608148..e9d7b3c75 100644 --- a/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs +++ b/extensions/Worker.Extensions.CosmosDB/src/Config/CosmosDBExtensionOptions.cs @@ -11,10 +11,5 @@ public class CosmosDBExtensionOptions /// Gets or sets the CosmosClientOptions. /// public CosmosClientOptions ClientOptions { get; set; } = new() { ConnectionMode = ConnectionMode.Gateway }; - - internal CosmosDBExtensionOptions Clone() - { - return (CosmosDBExtensionOptions)this.MemberwiseClone(); - } } -} \ No newline at end of file +} diff --git a/extensions/Worker.Extensions.CosmosDB/src/Extensions/CloningExtensions.cs b/extensions/Worker.Extensions.CosmosDB/src/Extensions/CloningExtensions.cs new file mode 100644 index 000000000..f7146c1d1 --- /dev/null +++ b/extensions/Worker.Extensions.CosmosDB/src/Extensions/CloningExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Reflection; +using Microsoft.Azure.Cosmos; + +namespace Microsoft.Azure.Functions.Worker +{ + internal static class CloningExtensions + { + public static T MemberwiseClone(this T original) + { + if (original is null) + { + throw new ArgumentNullException(nameof(original)); + } + + // Get the type of the object + Type type = original.GetType(); + + // Get the internal Clone method + MethodInfo cloneMethod = type.GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic); + + if (cloneMethod is null) + { + throw new InvalidOperationException("The MemberwiseClone method could not be found."); + } + + // Invoke the Clone method + return (T)cloneMethod.Invoke(original, null); + } + } +}