diff --git a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs index b1a0d912b8c..1def80174de 100644 --- a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs +++ b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs @@ -62,6 +62,19 @@ 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 factory. + /// + /// + /// To avoid multiple instances being created use lambdas: + /// + /// .HttpClientFactory(static () => new HttpClient()) + /// + /// A function that returns an . + 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..fd1698d2df8 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(); } @@ -581,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) { 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..fdc1ff716ed 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)); + Func httpClientFactory = () => new HttpClient(); + Test( + o => o.HttpClientFactory(httpClientFactory), + o => Assert.Same(httpClientFactory, o.HttpClientFactory) + ); } [ConditionalFact] @@ -101,4 +106,3 @@ private void Throws(Action cosmosOptionsAction } } } -