diff --git a/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs b/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs
index 7b2ab4d65b..33490963ea 100644
--- a/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs
+++ b/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs
@@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+ using System.Net.Http;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
@@ -423,6 +424,15 @@ public PortReuseMode? PortReuseMode
set;
}
+ ///
+ /// Gets or sets a delegate to use to obtain an HttpClient instance to be used for HTTPS communication.
+ ///
+ public Func HttpClientFactory
+ {
+ get;
+ set;
+ }
+
///
/// (Direct/TCP) This is an advanced setting that controls the number of TCP connections that will be opened eagerly to each Cosmos DB back-end.
///
diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
index d5d4ec4a95..614c9d91fe 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
@@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos
using System.Data.Common;
using System.Linq;
using System.Net;
+ using System.Net.Http;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
@@ -66,6 +67,7 @@ public class CosmosClientOptions
private int? maxTcpConnectionsPerEndpoint;
private PortReuseMode? portReuseMode;
private IWebProxy webProxy;
+ private Func httpClientFactory;
///
/// Creates a new CosmosClientOptions
@@ -321,6 +323,11 @@ public IWebProxy WebProxy
{
throw new ArgumentException($"{nameof(this.WebProxy)} requires {nameof(this.ConnectionMode)} to be set to {nameof(ConnectionMode.Gateway)}");
}
+
+ if (this.HttpClientFactory != null)
+ {
+ throw new ArgumentException($"{nameof(this.WebProxy)} cannot be set along {nameof(this.HttpClientFactory)}");
+ }
}
}
@@ -426,6 +433,32 @@ public CosmosSerializer Serializer
///
public bool EnableTcpConnectionEndpointRediscovery { get; set; } = false;
+ ///
+ /// Gets or sets a delegate to use to obtain an HttpClient instance to be used for HTTPS communication.
+ ///
+ ///
+ ///
+ /// HTTPS communication is used when is set to for all operations and when is (default) for metadata operations.
+ ///
+ ///
+ /// Useful in scenarios where the application is using a pool of HttpClient instances to be shared, like ASP.NET Core applications with IHttpClientFactory or Blazor WebAssembly applications.
+ ///
+ ///
+ [JsonIgnore]
+ public Func HttpClientFactory
+ {
+ get => this.httpClientFactory;
+ set
+ {
+ if (this.WebProxy != null)
+ {
+ throw new ArgumentException($"{nameof(this.HttpClientFactory)} cannot be set along {nameof(this.WebProxy)}");
+ }
+
+ this.httpClientFactory = value;
+ }
+ }
+
///
/// Gets or sets the connection protocol when connecting to the Azure Cosmos service.
///
@@ -556,7 +589,8 @@ internal ConnectionPolicy GetConnectionPolicy()
MaxTcpConnectionsPerEndpoint = this.MaxTcpConnectionsPerEndpoint,
EnableEndpointDiscovery = !this.LimitToEndpoint,
PortReuseMode = this.portReuseMode,
- EnableTcpConnectionEndpointRediscovery = this.EnableTcpConnectionEndpointRediscovery
+ EnableTcpConnectionEndpointRediscovery = this.EnableTcpConnectionEndpointRediscovery,
+ HttpClientFactory = this.httpClientFactory
};
if (this.ApplicationRegion != null)
@@ -737,6 +771,11 @@ private string GetUserAgentFeatures()
features |= CosmosClientOptionsFeatures.AllowBulkExecution;
}
+ if (this.HttpClientFactory != null)
+ {
+ features |= CosmosClientOptionsFeatures.HttpClientFactory;
+ }
+
if (features == CosmosClientOptionsFeatures.NoFeatures)
{
return null;
diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptionsFeatures.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptionsFeatures.cs
index 02eef19178..b81b80b252 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClientOptionsFeatures.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptionsFeatures.cs
@@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos
internal enum CosmosClientOptionsFeatures
{
NoFeatures = 0,
- AllowBulkExecution = 1
+ AllowBulkExecution = 1,
+ HttpClientFactory = 2
}
}
diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs
index 4c830876e7..1f86e7cc78 100644
--- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs
+++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs
@@ -1117,7 +1117,23 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeClientFac
this.EnsureValidOverwrite(this.desiredConsistencyLevel.Value);
}
- GatewayStoreModel gatewayStoreModel = new GatewayStoreModel(
+ GatewayStoreModel gatewayStoreModel;
+ if (this.ConnectionPolicy.HttpClientFactory != null)
+ {
+ gatewayStoreModel = new GatewayStoreModel(
+ this.GlobalEndpointManager,
+ this.sessionContainer,
+ this.ConnectionPolicy.RequestTimeout,
+ (Cosmos.ConsistencyLevel)this.accountServiceConfiguration.DefaultConsistencyLevel,
+ this.eventSource,
+ this.serializerSettings,
+ this.ConnectionPolicy.UserAgentContainer,
+ this.ApiType,
+ this.ConnectionPolicy.HttpClientFactory);
+ }
+ else
+ {
+ gatewayStoreModel = new GatewayStoreModel(
this.GlobalEndpointManager,
this.sessionContainer,
this.ConnectionPolicy.RequestTimeout,
@@ -1127,6 +1143,7 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeClientFac
this.ConnectionPolicy.UserAgentContainer,
this.ApiType,
this.httpMessageHandler);
+ }
this.GatewayStoreModel = gatewayStoreModel;
diff --git a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
index 44a18f4ee7..b8f0e4bf77 100644
--- a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
+++ b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
@@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.Fluent
{
using System;
using System.Net;
+ using System.Net.Http;
using Microsoft.Azure.Cosmos.Core.Trace;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
@@ -391,6 +392,26 @@ public CosmosClientBuilder WithBulkExecution(bool enabled)
return this;
}
+ ///
+ /// Sets a delegate to use to obtain an HttpClient instance to be used for HTTPS communication.
+ ///
+ /// A delegate function to generate instances of HttpClient.
+ ///
+ ///
+ /// HTTPS communication is used when is set to for all operations and when is (default) for metadata operations.
+ ///
+ ///
+ /// Useful in scenarios where the application is using a pool of HttpClient instances to be shared, like ASP.NET Core applications with IHttpClientFactory or Blazor WebAssembly applications.
+ ///
+ ///
+ /// The object
+ ///
+ public CosmosClientBuilder WithHttpClientFactory(Func httpClientFactory)
+ {
+ this.clientOptions.HttpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
+ return this;
+ }
+
///
/// Provider that allows encrypting and decrypting data.
/// See https://aka.ms/CosmosClientEncryption for more information on client-side encryption support in Azure Cosmos DB.
diff --git a/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs b/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs
index fea5a68ef2..1888d5ccd7 100644
--- a/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs
+++ b/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs
@@ -31,24 +31,80 @@ internal class GatewayStoreModel : IStoreModel, IDisposable
private GatewayStoreClient gatewayStoreClient;
private CookieContainer cookieJar;
- public GatewayStoreModel(
+ private GatewayStoreModel(
GlobalEndpointManager endpointManager,
ISessionContainer sessionContainer,
- TimeSpan requestTimeout,
ConsistencyLevel defaultConsistencyLevel,
- DocumentClientEventSource eventSource,
- JsonSerializerSettings serializerSettings,
- UserAgentContainer userAgent,
- ApiType apiType = ApiType.None,
- HttpMessageHandler messageHandler = null)
+ DocumentClientEventSource eventSource)
{
// CookieContainer is not really required, but is helpful in debugging.
this.cookieJar = new CookieContainer();
this.endpointManager = endpointManager;
- HttpClient httpClient = new HttpClient(messageHandler ?? new HttpClientHandler { CookieContainer = this.cookieJar });
this.sessionContainer = sessionContainer;
this.defaultConsistencyLevel = defaultConsistencyLevel;
+ this.eventSource = eventSource;
+ }
+
+ public GatewayStoreModel(
+ GlobalEndpointManager endpointManager,
+ ISessionContainer sessionContainer,
+ TimeSpan requestTimeout,
+ ConsistencyLevel defaultConsistencyLevel,
+ DocumentClientEventSource eventSource,
+ JsonSerializerSettings serializerSettings,
+ UserAgentContainer userAgent,
+ ApiType apiType,
+ HttpMessageHandler messageHandler)
+ : this(endpointManager,
+ sessionContainer,
+ defaultConsistencyLevel,
+ eventSource)
+ {
+ this.InitializeGatewayStoreClient(
+ requestTimeout,
+ serializerSettings,
+ userAgent,
+ apiType,
+ new HttpClient(messageHandler ?? new HttpClientHandler { CookieContainer = this.cookieJar }));
+ }
+ public GatewayStoreModel(
+ GlobalEndpointManager endpointManager,
+ ISessionContainer sessionContainer,
+ TimeSpan requestTimeout,
+ ConsistencyLevel defaultConsistencyLevel,
+ DocumentClientEventSource eventSource,
+ JsonSerializerSettings serializerSettings,
+ UserAgentContainer userAgent,
+ ApiType apiType,
+ Func httpClientFactory)
+ : this(endpointManager,
+ sessionContainer,
+ defaultConsistencyLevel,
+ eventSource)
+ {
+ HttpClient httpClient = httpClientFactory();
+ if (httpClient == null)
+ {
+ throw new InvalidOperationException("HttpClientFactory did not produce an HttpClient");
+ }
+
+ this.InitializeGatewayStoreClient(
+ requestTimeout,
+ serializerSettings,
+ userAgent,
+ apiType,
+ httpClient);
+
+ }
+
+ private void InitializeGatewayStoreClient(
+ TimeSpan requestTimeout,
+ JsonSerializerSettings serializerSettings,
+ UserAgentContainer userAgent,
+ ApiType apiType,
+ HttpClient httpClient)
+ {
// Use max of client specified and our own request timeout value when sending
// requests to gateway. Otherwise, we will have gateway's transient
// error hiding retries are of no use.
@@ -65,12 +121,10 @@ public GatewayStoreModel(
httpClient.DefaultRequestHeaders.Add(HttpConstants.HttpHeaders.Accept, RuntimeConstants.MediaTypes.Json);
- this.eventSource = eventSource;
this.gatewayStoreClient = new GatewayStoreClient(
httpClient,
this.eventSource,
serializerSettings);
-
}
public virtual async Task ProcessMessageAsync(DocumentServiceRequest request, CancellationToken cancellationToken = default(CancellationToken))
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs
index cb56e26825..ea61806e3c 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs
@@ -15,6 +15,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -301,6 +302,45 @@ await Assert.ThrowsExceptionAsync(async () => {
DatabaseResponse databaseResponse = await cosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString());
});
}
+
+ [TestMethod]
+ public async Task HttpClientFactorySmokeTest()
+ {
+ HttpClient client = new HttpClient();
+ Mock> factory = new Mock>();
+ factory.Setup(f => f()).Returns(client);
+ CosmosClient cosmosClient = new CosmosClient(
+ ConfigurationManager.AppSettings["GatewayEndpoint"],
+ ConfigurationManager.AppSettings["MasterKey"],
+ new CosmosClientOptions
+ {
+ ApplicationName = "test",
+ ConnectionMode = ConnectionMode.Gateway,
+ ConnectionProtocol = Protocol.Https,
+ HttpClientFactory = factory.Object
+ }
+ );
+
+ string someId = Guid.NewGuid().ToString();
+ Cosmos.Database database = null;
+ try
+ {
+ database = await cosmosClient.CreateDatabaseAsync(someId);
+ Cosmos.Container container = await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id");
+ await container.CreateItemAsync(new { id = someId });
+ await container.ReadItemAsync(someId, new Cosmos.PartitionKey(someId));
+ await container.DeleteItemAsync(someId, new Cosmos.PartitionKey(someId));
+ await container.DeleteContainerAsync();
+ Mock.Get(factory.Object).Verify(f => f(), Times.Once);
+ }
+ finally
+ {
+ if (database!= null)
+ {
+ await database.DeleteAsync();
+ }
+ }
+ }
}
internal static class StringHelper
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/UserAgentTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/UserAgentTests.cs
index 8d728b43ba..0733d887a3 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/UserAgentTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/UserAgentTests.cs
@@ -110,10 +110,13 @@ public async Task VerifyUserAgentWithFeatures(bool useMacOs)
this.SetEnvironmentInformation(useMacOs);
const string suffix = " UserApplicationName/1.0";
+ CosmosClientOptionsFeatures featuresFlags = CosmosClientOptionsFeatures.NoFeatures;
+ featuresFlags |= CosmosClientOptionsFeatures.AllowBulkExecution;
+ featuresFlags |= CosmosClientOptionsFeatures.HttpClientFactory;
- string features = Convert.ToString((int)CosmosClientOptionsFeatures.AllowBulkExecution, 2).PadLeft(8, '0');
+ string features = Convert.ToString((int)featuresFlags, 2).PadLeft(8, '0');
- using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder.WithApplicationName(suffix).WithBulkExecution(true)))
+ using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder.WithApplicationName(suffix).WithBulkExecution(true).WithHttpClientFactory(() => new HttpClient())))
{
Cosmos.UserAgentContainer userAgentContainer = client.ClientOptions.GetConnectionPolicy().UserAgentContainer;
@@ -130,7 +133,7 @@ public async Task VerifyUserAgentWithFeatures(bool useMacOs)
await db.DeleteAsync();
}
- using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder.WithApplicationName(suffix).WithBulkExecution(false)))
+ using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder.WithApplicationName(suffix)))
{
Cosmos.UserAgentContainer userAgentContainer = client.ClientOptions.GetConnectionPolicy().UserAgentContainer;
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
index 606eae3742..c71d2f0af5 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
@@ -21,6 +21,7 @@ public class CosmosClientOptionsUnitTests
{
public const string AccountEndpoint = "https://localhost:8081/";
public const string ConnectionString = "AccountEndpoint=https://localtestcosmos.documents.azure.com:443/;AccountKey=425Mcv8CXQqzRNCgFNjIhT424GK99CKJvASowTnq15Vt8LeahXTcN5wt3342vQ==;";
+ public Func HttpClientFactoryDelegate = () => new HttpClient();
[TestMethod]
public void VerifyCosmosConfigurationPropertiesGetUpdated()
@@ -74,6 +75,7 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
Assert.IsNull(clientOptions.WebProxy);
Assert.IsFalse(clientOptions.LimitToEndpoint);
Assert.IsFalse(clientOptions.EnableTcpConnectionEndpointRediscovery);
+ Assert.IsNull(clientOptions.HttpClientFactory);
//Verify GetConnectionPolicy returns the correct values for default
ConnectionPolicy policy = clientOptions.GetConnectionPolicy();
@@ -87,6 +89,7 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
Assert.IsNull(policy.MaxTcpConnectionsPerEndpoint);
Assert.IsTrue(policy.EnableEndpointDiscovery);
Assert.IsFalse(policy.EnableTcpConnectionEndpointRediscovery);
+ Assert.IsNull(policy.HttpClientFactory);
cosmosClientBuilder.WithApplicationRegion(region)
.WithConnectionModeGateway(maxConnections, webProxy)
@@ -353,6 +356,41 @@ public void VerifyApplicationRegionSettingsWithPreferredRegions()
cosmosClientOptions.GetConnectionPolicy();
}
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void VerifyWebProxyHttpClientFactorySet()
+ {
+ CosmosClientOptions cosmosClientOptions = new CosmosClientOptions();
+ cosmosClientOptions.WebProxy = Mock.Of();
+ cosmosClientOptions.HttpClientFactory = () => new HttpClient();
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void VerifyHttpClientFactoryWebProxySet()
+ {
+ CosmosClientOptions cosmosClientOptions = new CosmosClientOptions();
+ cosmosClientOptions.HttpClientFactory = () => new HttpClient();
+ cosmosClientOptions.WebProxy = Mock.Of();
+ }
+
+ [TestMethod]
+ public void HttpClientFactoryBuildsConnectionPolicy()
+ {
+ string endpoint = AccountEndpoint;
+ string key = Guid.NewGuid().ToString();
+ CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(
+ accountEndpoint: endpoint,
+ authKeyOrResourceToken: key)
+ .WithHttpClientFactory(this.HttpClientFactoryDelegate);
+ CosmosClient cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient());
+ CosmosClientOptions clientOptions = cosmosClient.ClientOptions;
+
+ Assert.AreEqual(clientOptions.HttpClientFactory, this.HttpClientFactoryDelegate);
+ ConnectionPolicy policy = clientOptions.GetConnectionPolicy();
+ Assert.AreEqual(policy.HttpClientFactory, this.HttpClientFactoryDelegate);
+ }
+
[TestMethod]
public void WithLimitToEndpointAffectsEndpointDiscovery()
{
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
index 27589cc42c..a5b1ffb912 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
@@ -1482,6 +1482,18 @@
],
"MethodInfo": "System.Collections.ObjectModel.Collection`1[Microsoft.Azure.Cosmos.RequestHandler] get_CustomHandlers()"
},
+ "System.Func`1[System.Net.Http.HttpClient] get_HttpClientFactory()": {
+ "Type": "Method",
+ "Attributes": [],
+ "MethodInfo": "System.Func`1[System.Net.Http.HttpClient] get_HttpClientFactory()"
+ },
+ "System.Func`1[System.Net.Http.HttpClient] HttpClientFactory[Newtonsoft.Json.JsonIgnoreAttribute()]": {
+ "Type": "Property",
+ "Attributes": [
+ "JsonIgnoreAttribute"
+ ],
+ "MethodInfo": null
+ },
"System.Net.IWebProxy get_WebProxy()": {
"Type": "Method",
"Attributes": [],
@@ -1673,6 +1685,11 @@
"Attributes": [],
"MethodInfo": "Void set_GatewayModeMaxConnectionLimit(Int32)"
},
+ "Void set_HttpClientFactory(System.Func`1[System.Net.Http.HttpClient])": {
+ "Type": "Method",
+ "Attributes": [],
+ "MethodInfo": "Void set_HttpClientFactory(System.Func`1[System.Net.Http.HttpClient])"
+ },
"Void set_IdleTcpConnectionTimeout(System.Nullable`1[System.TimeSpan])": {
"Type": "Method",
"Attributes": [],
@@ -2640,6 +2657,11 @@
"Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithCustomSerializer(Microsoft.Azure.Cosmos.CosmosSerializer)"
},
+ "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithHttpClientFactory(System.Func`1[System.Net.Http.HttpClient])": {
+ "Type": "Method",
+ "Attributes": [],
+ "MethodInfo": "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithHttpClientFactory(System.Func`1[System.Net.Http.HttpClient])"
+ },
"Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithLimitToEndpoint(Boolean)": {
"Type": "Method",
"Attributes": [],
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs
index 26541aed46..387ae365d1 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs
@@ -270,6 +270,62 @@ private async Task GatewayStoreModel_Exception_UpdateSessionTokenOnKnownExceptio
}
}
+ [TestMethod]
+ public void GatewayStoreModel_HttpClientFactory()
+ {
+ HttpClient staticHttpClient = new HttpClient();
+
+ Mock> mockFactory = new Mock>();
+ mockFactory.Setup(f => f()).Returns(staticHttpClient);
+
+ Mock mockDocumentClient = new Mock();
+ mockDocumentClient.Setup(client => client.ServiceEndpoint).Returns(new Uri("https://foo"));
+
+ GlobalEndpointManager endpointManager = new GlobalEndpointManager(mockDocumentClient.Object, new ConnectionPolicy());
+ SessionContainer sessionContainer = new SessionContainer(string.Empty);
+ DocumentClientEventSource eventSource = DocumentClientEventSource.Instance;
+ GatewayStoreModel storeModel = new GatewayStoreModel(
+ endpointManager,
+ sessionContainer,
+ TimeSpan.FromSeconds(5),
+ ConsistencyLevel.Eventual,
+ eventSource,
+ null,
+ new UserAgentContainer(),
+ ApiType.None,
+ mockFactory.Object);
+
+ Mock.Get(mockFactory.Object)
+ .Verify(f => f(), Times.Once);
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void GatewayStoreModel_HttpClientFactory_IfNull()
+ {
+ HttpClient staticHttpClient = null;
+
+ Mock> mockFactory = new Mock>();
+ mockFactory.Setup(f => f()).Returns(staticHttpClient);
+
+ Mock mockDocumentClient = new Mock();
+ mockDocumentClient.Setup(client => client.ServiceEndpoint).Returns(new Uri("https://foo"));
+
+ GlobalEndpointManager endpointManager = new GlobalEndpointManager(mockDocumentClient.Object, new ConnectionPolicy());
+ SessionContainer sessionContainer = new SessionContainer(string.Empty);
+ DocumentClientEventSource eventSource = DocumentClientEventSource.Instance;
+ GatewayStoreModel storeModel = new GatewayStoreModel(
+ endpointManager,
+ sessionContainer,
+ TimeSpan.FromSeconds(5),
+ ConsistencyLevel.Eventual,
+ eventSource,
+ null,
+ new UserAgentContainer(),
+ ApiType.None,
+ mockFactory.Object);
+ }
+
[TestMethod]
// Verify that for 429 exceptions, session token is not updated
public async Task GatewayStoreModel_Exception_NotUpdateSessionTokenOnKnownExceptions()