From 78df35202c5667c5f6d748d94b34011eee29fd0e Mon Sep 17 00:00:00 2001 From: David Perfors Date: Fri, 30 Jul 2021 16:23:35 +0200 Subject: [PATCH 1/6] Cosmos: Make it possible to configure a HttpClientFactory Fixes #21274 --- .../CosmosDbContextOptionsBuilder.cs | 7 +++++ .../Internal/CosmosDbOptionExtension.cs | 26 +++++++++++++++++++ .../Internal/CosmosSingletonOptions.cs | 10 +++++++ .../Internal/ICosmosSingletonOptions.cs | 8 ++++++ .../Internal/SingletonCosmosClientWrapper.cs | 5 ++++ .../CosmosDbContextOptionsExtensionsTests.cs | 5 ++++ 6 files changed, 61 insertions(+) diff --git a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs index b1a0d912b8c..cd01b25dd9a 100644 --- a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs +++ b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs @@ -62,6 +62,13 @@ public virtual CosmosDbContextOptionsBuilder Region(string region) public virtual CosmosDbContextOptionsBuilder LimitToEndpoint(bool enable = true) => WithOption(e => e.WithLimitToEndpoint(Check.NotNull(enable, nameof(enable)))); + /// + /// Configures the context to use a specific HttpClient. + /// + /// A functiont that returns a new HttpClient. + public virtual CosmosDbContextOptionsBuilder HttpClientFactory(Func? httpClientFactory) + => WithOption(e => e.WithHttpClientFactory(Check.NotNull(httpClientFactory, nameof(httpClientFactory)))); + /// /// Configures the context to use the provided connection mode. /// diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs index a57b2770422..a0bba3c7317 100644 --- a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs +++ b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs @@ -40,6 +40,7 @@ public class CosmosOptionsExtension : IDbContextOptionsExtension private int? _maxRequestsPerTcpConnection; private bool? _enableContentResponseOnWrite; private DbContextOptionsExtensionInfo? _info; + private Func? _httpClientFactory; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -74,6 +75,7 @@ protected CosmosOptionsExtension(CosmosOptionsExtension copyFrom) _gatewayModeMaxConnectionLimit = copyFrom._gatewayModeMaxConnectionLimit; _maxTcpConnectionsPerEndpoint = copyFrom._maxTcpConnectionsPerEndpoint; _maxRequestsPerTcpConnection = copyFrom._maxRequestsPerTcpConnection; + _httpClientFactory = copyFrom._httpClientFactory; } /// @@ -488,6 +490,29 @@ public virtual CosmosOptionsExtension ContentResponseOnWriteEnabled(bool enabled return clone; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual Func? HttpClientFactory => _httpClientFactory; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual CosmosOptionsExtension WithHttpClientFactory(Func? httpClientFactory) + { + var clone = Clone(); + + clone._httpClientFactory = httpClientFactory; + + return clone; + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -559,6 +584,7 @@ public override int GetServiceProviderHashCode() hashCode.Add(Extension._gatewayModeMaxConnectionLimit); hashCode.Add(Extension._maxTcpConnectionsPerEndpoint); hashCode.Add(Extension._maxRequestsPerTcpConnection); + hashCode.Add(Extension._httpClientFactory); _serviceProviderHash = hashCode.ToHashCode(); } diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosSingletonOptions.cs b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosSingletonOptions.cs index e04187a0be6..650c99834ae 100644 --- a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosSingletonOptions.cs +++ b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosSingletonOptions.cs @@ -137,6 +137,14 @@ public class CosmosSingletonOptions : ICosmosSingletonOptions /// public virtual bool? EnableContentResponseOnWrite { get; private set; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual Func? HttpClientFactory { get; private set; } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -162,6 +170,7 @@ public virtual void Initialize(IDbContextOptions options) GatewayModeMaxConnectionLimit = cosmosOptions.GatewayModeMaxConnectionLimit; MaxTcpConnectionsPerEndpoint = cosmosOptions.MaxTcpConnectionsPerEndpoint; MaxRequestsPerTcpConnection = cosmosOptions.MaxRequestsPerTcpConnection; + HttpClientFactory = cosmosOptions.HttpClientFactory; } } @@ -190,6 +199,7 @@ public virtual void Validate(IDbContextOptions options) || MaxTcpConnectionsPerEndpoint != cosmosOptions.MaxTcpConnectionsPerEndpoint || MaxRequestsPerTcpConnection != cosmosOptions.MaxRequestsPerTcpConnection || EnableContentResponseOnWrite != cosmosOptions.EnableContentResponseOnWrite + || HttpClientFactory != cosmosOptions.HttpClientFactory )) { throw new InvalidOperationException( diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/ICosmosSingletonOptions.cs b/src/EFCore.Cosmos/Infrastructure/Internal/ICosmosSingletonOptions.cs index 50e95172458..bc4782365a5 100644 --- a/src/EFCore.Cosmos/Infrastructure/Internal/ICosmosSingletonOptions.cs +++ b/src/EFCore.Cosmos/Infrastructure/Internal/ICosmosSingletonOptions.cs @@ -136,5 +136,13 @@ public interface ICosmosSingletonOptions : ISingletonOptions /// doing so can result in application failures when updating to a new Entity Framework Core release. /// bool? EnableContentResponseOnWrite { get; } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + Func? HttpClientFactory { get; } } } diff --git a/src/EFCore.Cosmos/Storage/Internal/SingletonCosmosClientWrapper.cs b/src/EFCore.Cosmos/Storage/Internal/SingletonCosmosClientWrapper.cs index 9da71d3178a..0d624f1ddb3 100644 --- a/src/EFCore.Cosmos/Storage/Internal/SingletonCosmosClientWrapper.cs +++ b/src/EFCore.Cosmos/Storage/Internal/SingletonCosmosClientWrapper.cs @@ -94,6 +94,11 @@ public SingletonCosmosClientWrapper(ICosmosSingletonOptions options) configuration.MaxRequestsPerTcpConnection = options.MaxRequestsPerTcpConnection.Value; } + if (options.HttpClientFactory != null) + { + configuration.HttpClientFactory = options.HttpClientFactory; + } + _options = configuration; } diff --git a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs index 4ea570c86f8..99422f62fd8 100644 --- a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs +++ b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs @@ -55,6 +55,11 @@ public void Can_create_options_with_valid_values() Test( o => o.IdleTcpConnectionTimeout(TimeSpan.FromMinutes(3)), o => Assert.Equal(TimeSpan.FromMinutes(3), o.IdleTcpConnectionTimeout)); + var httpClient = new HttpClient(); + Test( + o => o.HttpClientFactory(() => httpClient), + o => Assert.Same(httpClient, o.HttpClientFactory()) + ); } [ConditionalFact] From 31f983dd0e05fab0d219014368ce761b78cc21d4 Mon Sep 17 00:00:00 2001 From: David Perfors Date: Fri, 6 Aug 2021 22:47:50 +0200 Subject: [PATCH 2/6] Add missing comparison in ShouldUseSameServiceProvider. --- .../Infrastructure/Internal/CosmosDbOptionExtension.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs index a0bba3c7317..fd1698d2df8 100644 --- a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs +++ b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs @@ -607,7 +607,8 @@ public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo && Extension._idleTcpConnectionTimeout == otherInfo.Extension._idleTcpConnectionTimeout && Extension._gatewayModeMaxConnectionLimit == otherInfo.Extension._gatewayModeMaxConnectionLimit && Extension._maxTcpConnectionsPerEndpoint == otherInfo.Extension._maxTcpConnectionsPerEndpoint - && Extension._maxRequestsPerTcpConnection == otherInfo.Extension._maxRequestsPerTcpConnection; + && Extension._maxRequestsPerTcpConnection == otherInfo.Extension._maxRequestsPerTcpConnection + && Extension._httpClientFactory == otherInfo.Extension._httpClientFactory; public override void PopulateDebugInfo(IDictionary debugInfo) { From 6c033aa7de8bf1050c1c29c7d77be4263bd9b1e5 Mon Sep 17 00:00:00 2001 From: David Perfors Date: Fri, 6 Aug 2021 22:48:43 +0200 Subject: [PATCH 3/6] Update src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs Co-authored-by: Andriy Svyryd --- .../Infrastructure/CosmosDbContextOptionsBuilder.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs index cd01b25dd9a..19f7949f2c9 100644 --- a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs +++ b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs @@ -63,7 +63,13 @@ public virtual CosmosDbContextOptionsBuilder LimitToEndpoint(bool enable = true) => WithOption(e => e.WithLimitToEndpoint(Check.NotNull(enable, nameof(enable)))); /// - /// Configures the context to use a specific HttpClient. + /// + /// Configures the context to use a specific factory. + /// + /// + /// To avoid multiple instances being created use lambdas: + /// + /// .HttpClientFactory(static () => new HttpClient()) /// /// A functiont that returns a new HttpClient. public virtual CosmosDbContextOptionsBuilder HttpClientFactory(Func? httpClientFactory) From be14dfef5131c6a31403c2945562476cb6832f7c Mon Sep 17 00:00:00 2001 From: David Perfors Date: Fri, 6 Aug 2021 22:48:48 +0200 Subject: [PATCH 4/6] Update src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs Co-authored-by: Andriy Svyryd --- .../Infrastructure/CosmosDbContextOptionsBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs index 19f7949f2c9..1def80174de 100644 --- a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs +++ b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs @@ -71,7 +71,7 @@ public virtual CosmosDbContextOptionsBuilder LimitToEndpoint(bool enable = true) /// /// .HttpClientFactory(static () => new HttpClient()) /// - /// A functiont that returns a new HttpClient. + /// A function that returns an . public virtual CosmosDbContextOptionsBuilder HttpClientFactory(Func? httpClientFactory) => WithOption(e => e.WithHttpClientFactory(Check.NotNull(httpClientFactory, nameof(httpClientFactory)))); From 49d91981363b50f807d3ebb70cec2440392cd24d Mon Sep 17 00:00:00 2001 From: David Perfors Date: Fri, 6 Aug 2021 22:49:06 +0200 Subject: [PATCH 5/6] Update test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs Co-authored-by: Andriy Svyryd --- .../Extensions/CosmosDbContextOptionsExtensionsTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs index 99422f62fd8..742da27b312 100644 --- a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs +++ b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs @@ -55,9 +55,8 @@ public void Can_create_options_with_valid_values() Test( o => o.IdleTcpConnectionTimeout(TimeSpan.FromMinutes(3)), o => Assert.Equal(TimeSpan.FromMinutes(3), o.IdleTcpConnectionTimeout)); - var httpClient = new HttpClient(); Test( - o => o.HttpClientFactory(() => httpClient), + o => o.HttpClientFactory(static () => new HttpClient()), o => Assert.Same(httpClient, o.HttpClientFactory()) ); } @@ -106,4 +105,3 @@ private void Throws(Action cosmosOptionsAction } } } - From a3263927bcc9d517e3c113a09bac59946e41de05 Mon Sep 17 00:00:00 2001 From: David Perfors Date: Sat, 7 Aug 2021 08:01:47 +0200 Subject: [PATCH 6/6] Update test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs Co-authored-by: Andriy Svyryd --- .../Extensions/CosmosDbContextOptionsExtensionsTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs index 742da27b312..fdc1ff716ed 100644 --- a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs +++ b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs @@ -55,9 +55,10 @@ public void Can_create_options_with_valid_values() Test( o => o.IdleTcpConnectionTimeout(TimeSpan.FromMinutes(3)), o => Assert.Equal(TimeSpan.FromMinutes(3), o.IdleTcpConnectionTimeout)); + Func httpClientFactory = () => new HttpClient(); Test( - o => o.HttpClientFactory(static () => new HttpClient()), - o => Assert.Same(httpClient, o.HttpClientFactory()) + o => o.HttpClientFactory(httpClientFactory), + o => Assert.Same(httpClientFactory, o.HttpClientFactory) ); }