diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs
index 07fb7ea22e..4770d36398 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs
@@ -150,7 +150,7 @@ protected CosmosClient()
///
///
public CosmosClient(
- string connectionString,
+ string connectionString,
CosmosClientOptions clientOptions = null)
: this(
CosmosClientOptions.GetAccountEndpoint(connectionString),
@@ -612,18 +612,19 @@ internal void Init(
this.RequestHandler = clientPipelineBuilder.Build();
+ CosmosSerializer userSerializer = this.ClientOptions.GetCosmosSerializerWithWrapperOrDefault();
this.ResponseFactory = new CosmosResponseFactory(
defaultJsonSerializer: this.ClientOptions.PropertiesSerializer,
- userJsonSerializer: this.ClientOptions.CosmosSerializerWithWrapperOrDefault);
+ userJsonSerializer: userSerializer);
CosmosSerializer sqlQuerySpecSerializer = CosmosSqlQuerySpecJsonConverter.CreateSqlQuerySpecSerializer(
- this.ClientOptions.CosmosSerializerWithWrapperOrDefault,
- this.ClientOptions.PropertiesSerializer);
+ cosmosSerializer: userSerializer,
+ propertiesSerializer: this.ClientOptions.PropertiesSerializer);
this.ClientContext = new ClientContextCore(
client: this,
clientOptions: this.ClientOptions,
- userJsonSerializer: this.ClientOptions.CosmosSerializerWithWrapperOrDefault,
+ userJsonSerializer: userSerializer,
defaultJsonSerializer: this.ClientOptions.PropertiesSerializer,
sqlQuerySpecSerializer: sqlQuerySpecSerializer,
cosmosResponseFactory: this.ResponseFactory,
@@ -632,7 +633,7 @@ internal void Init(
documentQueryClient: new DocumentQueryClient(this.DocumentClient));
}
- internal async virtual Task GetAccountConsistencyLevelAsync()
+ internal virtual async Task GetAccountConsistencyLevelAsync()
{
if (!this.accountConsistencyLevel.HasValue)
{
diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
index 5f15d74769..c3a7afd2db 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
@@ -8,7 +8,6 @@ namespace Microsoft.Azure.Cosmos
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Linq;
- using System.Runtime.ConstrainedExecution;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
@@ -17,6 +16,18 @@ namespace Microsoft.Azure.Cosmos
///
/// Defines all the configurable options that the CosmosClient requires.
///
+ ///
+ /// An example on how to configure the serialization option to ignore null values
+ /// CosmosClientOptions clientOptions = new CosmosClientOptions()
+ /// {
+ /// SerializerOptions = new CosmosSerializationOptions(){
+ /// IgnoreNullValues = true
+ /// },
+ /// ConnectionMode = ConnectionMode.Gateway,
+ /// };
+ ///
+ /// CosmosClient client = new CosmosClient("endpoint", "key", clientOptions);
+ ///
public class CosmosClientOptions
{
///
@@ -39,11 +50,12 @@ public class CosmosClientOptions
///
private static readonly CosmosSerializer propertiesSerializer = new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer());
- private readonly Collection customHandlers;
private readonly string currentEnvironmentInformation;
private int gatewayModeMaxConnectionLimit;
private string applicationName;
+ private CosmosSerializationOptions serializerOptions;
+ private CosmosSerializer serializer;
///
/// Creates a new CosmosClientOptions
@@ -59,7 +71,7 @@ public CosmosClientOptions()
this.ConnectionMode = CosmosClientOptions.DefaultConnectionMode;
this.ConnectionProtocol = CosmosClientOptions.DefaultProtocol;
this.ApiType = CosmosClientOptions.DefaultApiType;
- this.customHandlers = new Collection();
+ this.CustomHandlers = new Collection();
}
///
@@ -132,10 +144,7 @@ public int GatewayModeMaxConnectionLimit
///
///
[JsonConverter(typeof(ClientOptionJsonConverter))]
- public Collection CustomHandlers
- {
- get => this.customHandlers;
- }
+ public Collection CustomHandlers { get; }
///
/// Get or set the connection mode used by the client when connecting to the Azure Cosmos DB service.
@@ -157,7 +166,7 @@ public Collection CustomHandlers
public ConsistencyLevel? ConsistencyLevel { get; set; }
///
- /// Get ot set the number of times client should retry on rate throttled requests.
+ /// Get or set the number of times client should retry on rate throttled requests.
///
///
public int? MaxRetryAttemptsOnRateLimitedRequests { get; set; }
@@ -171,6 +180,35 @@ public Collection CustomHandlers
///
public TimeSpan? MaxRetryWaitTimeOnRateLimitedRequests { get; set; }
+ ///
+ /// Get to set optional serializer options.
+ ///
+ ///
+ /// An example on how to configure the serialization option to ignore null values
+ /// CosmosClientOptions clientOptions = new CosmosClientOptions()
+ /// {
+ /// SerializerOptions = new CosmosSerializationOptions(){
+ /// IgnoreNullValues = true
+ /// }
+ /// };
+ ///
+ /// CosmosClient client = new CosmosClient("endpoint", "key", clientOptions);
+ ///
+ public CosmosSerializationOptions SerializerOptions
+ {
+ get => this.serializerOptions;
+ set
+ {
+ if (this.Serializer != null)
+ {
+ throw new ArgumentException(
+ $"{nameof(this.SerializerOptions)} is not compatible with {nameof(this.Serializer)}. Only one can be set. ");
+ }
+
+ this.serializerOptions = value;
+ }
+ }
+
///
/// Get to set an optional JSON serializer. The client will use it to serialize or de-serialize user's cosmos request/responses.
/// SDK owned types such as DatabaseProperties and ContainerProperties will always use the SDK default serializer.
@@ -182,10 +220,7 @@ public Collection CustomHandlers
///
/// // An example on how to configure the serializer to ignore null values
/// CosmosSerializer ignoreNullSerializer = new CosmosJsonDotNetSerializer(
- /// new JsonSerializerSettings()
- /// {
- /// NullValueHandling = NullValueHandling.Ignore
- /// });
+ /// NullValueHandling = NullValueHandling.Ignore);
///
/// CosmosClientOptions clientOptions = new CosmosClientOptions()
/// {
@@ -195,7 +230,20 @@ public Collection CustomHandlers
/// CosmosClient client = new CosmosClient("endpoint", "key", clientOptions);
///
[JsonConverter(typeof(ClientOptionJsonConverter))]
- public CosmosSerializer Serializer { get; set; }
+ public CosmosSerializer Serializer
+ {
+ get => this.serializer;
+ set
+ {
+ if (this.SerializerOptions != null)
+ {
+ throw new ArgumentException(
+ $"{nameof(this.Serializer)} is not compatible with {nameof(this.SerializerOptions)}. Only one can be set. ");
+ }
+
+ this.serializer = value;
+ }
+ }
///
/// A JSON serializer used by the CosmosClient to serialize or de-serialize cosmos request/responses.
@@ -205,12 +253,6 @@ public Collection CustomHandlers
[JsonConverter(typeof(ClientOptionJsonConverter))]
internal CosmosSerializer PropertiesSerializer => CosmosClientOptions.propertiesSerializer;
- ///
- /// Gets the user json serializer with the CosmosJsonSerializerWrapper or the default
- ///
- [JsonIgnore]
- internal CosmosSerializer CosmosSerializerWithWrapperOrDefault => this.Serializer == null ? this.PropertiesSerializer : new CosmosJsonSerializerWrapper(this.Serializer);
-
///
/// Gets or sets the connection protocol when connecting to the Azure Cosmos service.
///
@@ -309,6 +351,22 @@ public Collection CustomHandlers
///
internal bool? EnableCpuMonitor { get; set; }
+ ///
+ /// Gets the user json serializer with the CosmosJsonSerializerWrapper or the default
+ ///
+ internal CosmosSerializer GetCosmosSerializerWithWrapperOrDefault()
+ {
+ if (this.SerializerOptions != null)
+ {
+ CosmosJsonDotNetSerializer cosmosJsonDotNetSerializer = new CosmosJsonDotNetSerializer(this.SerializerOptions);
+ return new CosmosJsonSerializerWrapper(cosmosJsonDotNetSerializer);
+ }
+ else
+ {
+ return this.Serializer == null ? this.PropertiesSerializer : new CosmosJsonSerializerWrapper(this.Serializer);
+ }
+ }
+
internal CosmosClientOptions Clone()
{
CosmosClientOptions cloneConfiguration = (CosmosClientOptions)this.MemberwiseClone();
diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs
index 72bd457455..ba921dd142 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs
+++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs
@@ -29,7 +29,7 @@ static class CosmosElementSerializer
internal static CosmosArray ToCosmosElements(
MemoryStream memoryStream,
ResourceType resourceType,
- CosmosSerializationOptions cosmosSerializationOptions = null)
+ CosmosSerializationFormatOptions cosmosSerializationOptions = null)
{
if (!memoryStream.CanRead)
{
@@ -103,7 +103,7 @@ internal static Stream ToStream(
string containerRid,
IEnumerable cosmosElements,
ResourceType resourceType,
- CosmosSerializationOptions cosmosSerializationOptions = null)
+ CosmosSerializationFormatOptions cosmosSerializationOptions = null)
{
IJsonWriter jsonWriter;
if (cosmosSerializationOptions != null)
@@ -172,7 +172,7 @@ internal static IEnumerable Deserialize(
IEnumerable cosmosElements,
ResourceType resourceType,
CosmosSerializer jsonSerializer,
- CosmosSerializationOptions cosmosSerializationOptions = null)
+ CosmosSerializationFormatOptions cosmosSerializationOptions = null)
{
if (!cosmosElements.Any())
{
diff --git a/Microsoft.Azure.Cosmos/src/FeedOptions.cs b/Microsoft.Azure.Cosmos/src/FeedOptions.cs
index fa9f9dbb62..6552360e5f 100644
Binary files a/Microsoft.Azure.Cosmos/src/FeedOptions.cs and b/Microsoft.Azure.Cosmos/src/FeedOptions.cs differ
diff --git a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
index c5e5b32211..5a0bf04685 100644
--- a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
+++ b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
@@ -255,6 +255,19 @@ public CosmosClientBuilder WithThrottlingRetryOptions(TimeSpan maxRetryWaitTimeO
return this;
}
+ ///
+ /// Set a custom serializer option.
+ ///
+ /// The custom class that implements
+ /// The object
+ ///
+ ///
+ public CosmosClientBuilder WithSerializerOptions(CosmosSerializationOptions cosmosSerializerOptions)
+ {
+ this.clientOptions.SerializerOptions = cosmosSerializerOptions;
+ return this;
+ }
+
///
/// Set a custom JSON serializer.
///
@@ -262,8 +275,7 @@ public CosmosClientBuilder WithThrottlingRetryOptions(TimeSpan maxRetryWaitTimeO
/// The object
///
///
- public CosmosClientBuilder WithCustomSerializer(
- CosmosSerializer cosmosJsonSerializer)
+ public CosmosClientBuilder WithCustomSerializer(CosmosSerializer cosmosJsonSerializer)
{
this.clientOptions.Serializer = cosmosJsonSerializer;
return this;
diff --git a/Microsoft.Azure.Cosmos/src/RequestOptions/QueryRequestOptions.cs b/Microsoft.Azure.Cosmos/src/RequestOptions/QueryRequestOptions.cs
index 43110d3519..ca53dac640 100644
--- a/Microsoft.Azure.Cosmos/src/RequestOptions/QueryRequestOptions.cs
+++ b/Microsoft.Azure.Cosmos/src/RequestOptions/QueryRequestOptions.cs
@@ -140,7 +140,7 @@ public ConsistencyLevel? ConsistencyLevel
///
internal string SessionToken { get; set; }
- internal CosmosSerializationOptions CosmosSerializationOptions { get; set; }
+ internal CosmosSerializationFormatOptions CosmosSerializationOptions { get; set; }
///
/// Gets or sets the flag that enables skip take across partitions.
diff --git a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
index c581a1107e..cd761d3684 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
@@ -72,7 +72,7 @@ private QueryResponse(
///
internal ClientSideRequestStatistics RequestStatistics { get; }
- internal virtual CosmosSerializationOptions CosmosSerializationOptions { get; set; }
+ internal virtual CosmosSerializationFormatOptions CosmosSerializationOptions { get; set; }
internal bool GetHasMoreResults()
{
@@ -137,7 +137,7 @@ internal class QueryResponse : FeedResponse
{
private readonly IEnumerable cosmosElements;
private readonly CosmosSerializer jsonSerializer;
- private readonly CosmosSerializationOptions serializationOptions;
+ private readonly CosmosSerializationFormatOptions serializationOptions;
private IEnumerable resources;
private QueryResponse(
@@ -145,7 +145,7 @@ private QueryResponse(
IEnumerable cosmosElements,
CosmosQueryResponseMessageHeaders responseMessageHeaders,
CosmosSerializer jsonSerializer,
- CosmosSerializationOptions serializationOptions)
+ CosmosSerializationFormatOptions serializationOptions)
{
this.cosmosElements = cosmosElements;
this.QueryHeaders = responseMessageHeaders;
diff --git a/Microsoft.Azure.Cosmos/src/CosmosJsonDotNetSerializer.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs
similarity index 58%
rename from Microsoft.Azure.Cosmos/src/CosmosJsonDotNetSerializer.cs
rename to Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs
index 12aee89848..a0e0187a85 100644
--- a/Microsoft.Azure.Cosmos/src/CosmosJsonDotNetSerializer.cs
+++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs
@@ -7,11 +7,12 @@ namespace Microsoft.Azure.Cosmos
using System.IO;
using System.Text;
using Newtonsoft.Json;
+ using Newtonsoft.Json.Serialization;
///
- /// The default Cosmos JSON.NET serializer
+ /// The default Cosmos JSON.NET serializer.
///
- public sealed class CosmosJsonDotNetSerializer : CosmosSerializer
+ internal sealed class CosmosJsonDotNetSerializer : CosmosSerializer
{
private static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true);
private readonly JsonSerializer Serializer;
@@ -19,20 +20,48 @@ public sealed class CosmosJsonDotNetSerializer : CosmosSerializer
///
/// Create a serializer that uses the JSON.net serializer
///
- /// Optional serializer settings
- public CosmosJsonDotNetSerializer(JsonSerializerSettings jsonSerializerSettings = null)
+ ///
+ /// This is internal to reduce exposure of JSON.net types so
+ /// it is easier to convert to System.Text.Json
+ ///
+ internal CosmosJsonDotNetSerializer()
{
- if (jsonSerializerSettings == null)
+ this.Serializer = JsonSerializer.Create();
+ }
+
+ ///
+ /// Create a serializer that uses the JSON.net serializer
+ ///
+ ///
+ /// This is internal to reduce exposure of JSON.net types so
+ /// it is easier to convert to System.Text.Json
+ ///
+ internal CosmosJsonDotNetSerializer(CosmosSerializationOptions cosmosSerializerOptions)
+ {
+ JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
{
- jsonSerializerSettings = new JsonSerializerSettings()
- {
- NullValueHandling = NullValueHandling.Include
- };
- }
+ NullValueHandling = cosmosSerializerOptions.IgnoreNullValues ? NullValueHandling.Ignore : NullValueHandling.Include,
+ Formatting = cosmosSerializerOptions.Indented ? Formatting.Indented : Formatting.None,
+ ContractResolver = cosmosSerializerOptions.PropertyNamingPolicy == CosmosPropertyNamingPolicy.CamelCase
+ ? new CamelCasePropertyNamesContractResolver()
+ : null
+ };
this.Serializer = JsonSerializer.Create(jsonSerializerSettings);
}
+ ///
+ /// Create a serializer that uses the JSON.net serializer
+ ///
+ ///
+ /// This is internal to reduce exposure of JSON.net types so
+ /// it is easier to convert to System.Text.Json
+ ///
+ internal CosmosJsonDotNetSerializer(JsonSerializerSettings jsonSerializerSettings)
+ {
+ this.Serializer = JsonSerializer.Create(jsonSerializerSettings);
+ }
+
///
/// Convert a Stream to the passed in type.
///
@@ -45,7 +74,7 @@ public override T FromStream(Stream stream)
{
if (typeof(Stream).IsAssignableFrom(typeof(T)))
{
- return (T)(object)(stream);
+ return (T)(object)stream;
}
using (StreamReader sr = new StreamReader(stream))
diff --git a/Microsoft.Azure.Cosmos/src/CosmosJsonSerializerWrapper.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonSerializerWrapper.cs
similarity index 100%
rename from Microsoft.Azure.Cosmos/src/CosmosJsonSerializerWrapper.cs
rename to Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonSerializerWrapper.cs
diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosPropertyNamingPolicy.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosPropertyNamingPolicy.cs
new file mode 100644
index 0000000000..ead587fa71
--- /dev/null
+++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosPropertyNamingPolicy.cs
@@ -0,0 +1,23 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+namespace Microsoft.Azure.Cosmos
+{
+ ///
+ /// Determines the naming policy used to convert a string-based name to another format, such as a camel-casing where the first letter is lower case.
+ ///
+ public enum CosmosPropertyNamingPolicy
+ {
+ ///
+ /// No custom naming policy.
+ /// The property name will be the same as the source.
+ ///
+ Default = 0,
+
+ ///
+ /// First letter in the property name is lower case.
+ ///
+ CamelCase = 1,
+ }
+}
diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosSerializationOptions.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationFormatOptions.cs
similarity index 94%
rename from Microsoft.Azure.Cosmos/src/Resource/CosmosSerializationOptions.cs
rename to Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationFormatOptions.cs
index 76c4eeb6ca..a9e9ca74a6 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/CosmosSerializationOptions.cs
+++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationFormatOptions.cs
@@ -6,7 +6,7 @@ namespace Microsoft.Azure.Cosmos
using System;
using Microsoft.Azure.Cosmos.Json;
- internal sealed class CosmosSerializationOptions
+ internal sealed class CosmosSerializationFormatOptions
{
public delegate IJsonNavigator CreateCustomNavigator(byte[] content);
@@ -27,7 +27,7 @@ internal sealed class CosmosSerializationOptions
///
public CreateCustomWriter CreateCustomWriterCallback { get; }
- public CosmosSerializationOptions(
+ public CosmosSerializationFormatOptions(
string contentSerializationFormat,
CreateCustomNavigator createCustomNavigator,
CreateCustomWriter createCustomWriter)
diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationOptions.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationOptions.cs
new file mode 100644
index 0000000000..965d824012
--- /dev/null
+++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializationOptions.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+namespace Microsoft.Azure.Cosmos
+{
+ ///
+ /// This class provides a way to configure basic
+ /// serializer settings.
+ ///
+ public sealed class CosmosSerializationOptions
+ {
+ ///
+ /// Create an instance of CosmosSerializationOptions
+ /// with the default values for the Cosmos SDK
+ ///
+ public CosmosSerializationOptions()
+ {
+ this.IgnoreNullValues = false;
+ this.Indented = false;
+ this.PropertyNamingPolicy = CosmosPropertyNamingPolicy.Default;
+ }
+
+ ///
+ /// Gets or sets if the serializer should ignore null properties
+ ///
+ ///
+ /// The default value is false
+ ///
+ public bool IgnoreNullValues { get; set; }
+
+ ///
+ /// Gets or sets if the serializer should use indentation
+ ///
+ ///
+ /// The default value is false
+ ///
+ public bool Indented { get; set; }
+
+ ///
+ /// Gets or sets whether the naming policy used to convert a string-based name to another format,
+ /// such as a camel-casing format.
+ ///
+ ///
+ /// The default value is CosmosPropertyNamingPolicy.Default
+ ///
+ public CosmosPropertyNamingPolicy PropertyNamingPolicy { get; set; }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos/src/CosmosSerializer.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializer.cs
similarity index 100%
rename from Microsoft.Azure.Cosmos/src/CosmosSerializer.cs
rename to Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializer.cs
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
index 89db954e14..c67e3e1048 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
@@ -1080,7 +1080,7 @@ public async Task ItemQueryStreamSerializationSetting()
IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 101, randomPartitionKey: true);
QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t ORDER BY t.taskNum");
- CosmosSerializationOptions options = new CosmosSerializationOptions(
+ CosmosSerializationFormatOptions options = new CosmosSerializationFormatOptions(
ContentSerializationFormat.CosmosBinary.ToString(),
(content) => JsonNavigator.Create(content),
() => JsonWriter.Create(JsonSerializationFormat.Binary));
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ContractEnforcement.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ContractEnforcement.cs
index 492a836fec..9bf7b2c51f 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ContractEnforcement.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ContractEnforcement.cs
@@ -18,8 +18,8 @@ public class ContractEnforcement
[TestMethod]
public void ContractChanges()
{
- Assert.IsTrue(
- ContractEnforcement.CheckBreakingChanges("Microsoft.Azure.Cosmos.Client", BaselinePath, BreakingChangesPath),
+ Assert.IsFalse(
+ ContractEnforcement.DoesContractContainBreakingChanges("Microsoft.Azure.Cosmos.Client", BaselinePath, BreakingChangesPath),
$@"Public API has changed. If this is expected, then refresh {BaselinePath} with {Environment.NewLine} Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/testbaseline.cmd /update after this test is run locally. To see the differences run testbaselines.cmd /diff"
);
}
@@ -69,7 +69,8 @@ private static IEnumerable RemoveDebugSpecificAttributes(IE
!x.AttributeType.Name.Contains("NonVersionableAttribute") &&
!x.AttributeType.Name.Contains("ReliabilityContractAttribute") &&
!x.AttributeType.Name.Contains("NonVersionableAttribute") &&
- !x.AttributeType.Name.Contains("DebuggerStepThroughAttribute")
+ !x.AttributeType.Name.Contains("DebuggerStepThroughAttribute") &&
+ !x.AttributeType.Name.Contains("IsReadOnlyAttribute")
);
}
@@ -115,7 +116,7 @@ private static TypeTree BuildTypeTree(TypeTree root, Type[] types)
return root;
}
- private static bool CheckBreakingChanges(string dllName, string baselinePath, string breakingChangesPath)
+ private static bool DoesContractContainBreakingChanges(string dllName, string baselinePath, string breakingChangesPath)
{
TypeTree locally = new TypeTree(typeof(object));
ContractEnforcement.BuildTypeTree(locally, ContractEnforcement.GetAssemblyLocally(dllName).GetExportedTypes());
@@ -126,28 +127,16 @@ private static bool CheckBreakingChanges(string dllName, string baselinePath, st
File.WriteAllText($"{breakingChangesPath}", localJson);
string baselineJson = JsonConvert.SerializeObject(baseline, Formatting.Indented);
- for (int i=0; i < baselineJson.Length && i < localJson.Length; i++)
+ System.Diagnostics.Trace.TraceWarning($"String length Expected: {baselineJson.Length};Actual:{localJson.Length}");
+ if (string.Equals(localJson, baselineJson, StringComparison.InvariantCulture))
{
- if (baselineJson[i] != localJson[i])
- {
- // First byte of diff, trace next 200 bytes if-exists
- ContractEnforcement.TraceSubpartIfExists(baselineJson, 0, 200);
- ContractEnforcement.TraceSubpartIfExists(localJson, 0, 200);
- }
- }
-
- return baselineJson == localJson;
- }
-
- private static void TraceSubpartIfExists(string input, int position, int desiredLength)
- {
- if (position + desiredLength > input.Length)
- {
- System.Diagnostics.Trace.TraceWarning($"baseline: {input.Substring(position)}");
+ return false;
}
else
{
- System.Diagnostics.Trace.TraceWarning($"baseline: {input.Substring(position, desiredLength)}");
+ System.Diagnostics.Trace.TraceWarning($"Expected: {baselineJson}");
+ System.Diagnostics.Trace.TraceWarning($"Actual: {localJson}");
+ return true;
}
}
}
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 e562f6f443..2cf8e442fb 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs
@@ -5,8 +5,7 @@
namespace Microsoft.Azure.Cosmos.Tests
{
using System;
- using System.Linq;
- using System.Reflection;
+ using System.IO;
using Microsoft.Azure.Cosmos.Client.Core.Tests;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Documents;
@@ -34,6 +33,11 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
ApiType apiType = ApiType.Sql;
int maxRetryAttemptsOnThrottledRequests = 9999;
TimeSpan maxRetryWaitTime = TimeSpan.FromHours(6);
+ CosmosSerializationOptions cosmosSerializerOptions = new CosmosSerializationOptions()
+ {
+ IgnoreNullValues = true,
+ PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase,
+ };
CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(
accountEndpoint: endpoint,
@@ -53,6 +57,8 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
Assert.AreNotEqual(userAgentSuffix, clientOptions.ApplicationName);
Assert.AreNotEqual(apiType, clientOptions.ApiType);
Assert.AreEqual(0, clientOptions.CustomHandlers.Count);
+ Assert.IsNull(clientOptions.SerializerOptions);
+ Assert.IsNull(clientOptions.Serializer);
//Verify GetConnectionPolicy returns the correct values for default
ConnectionPolicy policy = clientOptions.GetConnectionPolicy();
@@ -67,7 +73,8 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
.WithApplicationName(userAgentSuffix)
.AddCustomHandlers(preProcessHandler)
.WithApiType(apiType)
- .WithThrottlingRetryOptions(maxRetryWaitTime, maxRetryAttemptsOnThrottledRequests);
+ .WithThrottlingRetryOptions(maxRetryWaitTime, maxRetryAttemptsOnThrottledRequests)
+ .WithSerializerOptions(cosmosSerializerOptions);
cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient());
clientOptions = cosmosClient.ClientOptions;
@@ -82,6 +89,9 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated()
Assert.AreEqual(apiType, clientOptions.ApiType);
Assert.AreEqual(maxRetryAttemptsOnThrottledRequests, clientOptions.MaxRetryAttemptsOnRateLimitedRequests);
Assert.AreEqual(maxRetryWaitTime, clientOptions.MaxRetryWaitTimeOnRateLimitedRequests);
+ Assert.AreEqual(cosmosSerializerOptions.IgnoreNullValues, clientOptions.SerializerOptions.IgnoreNullValues);
+ Assert.AreEqual(cosmosSerializerOptions.PropertyNamingPolicy, clientOptions.SerializerOptions.PropertyNamingPolicy);
+ Assert.AreEqual(cosmosSerializerOptions.Indented, clientOptions.SerializerOptions.Indented);
//Verify GetConnectionPolicy returns the correct values
policy = clientOptions.GetConnectionPolicy();
@@ -119,8 +129,8 @@ public void ThrowOnNullEndpoint()
[TestMethod]
public void UserAgentContainsEnvironmentInformation()
{
- var environmentInformation = new EnvironmentInformation();
- var expectedValue = environmentInformation.ToString();
+ EnvironmentInformation environmentInformation = new EnvironmentInformation();
+ string expectedValue = environmentInformation.ToString();
CosmosClientOptions cosmosClientOptions = new CosmosClientOptions();
string userAgentSuffix = "testSuffix";
cosmosClientOptions.ApplicationName = userAgentSuffix;
@@ -133,6 +143,86 @@ public void UserAgentContainsEnvironmentInformation()
Assert.IsTrue(connectionPolicy.UserAgentSuffix.Contains(expectedValue));
}
+ [TestMethod]
+ public void GetCosmosSerializerWithWrapperOrDefaultTest()
+ {
+ CosmosJsonDotNetSerializer serializer = new CosmosJsonDotNetSerializer();
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ Serializer = serializer
+ };
+
+ CosmosSerializer cosmosSerializer = options.GetCosmosSerializerWithWrapperOrDefault();
+ Assert.AreNotEqual(cosmosSerializer, options.PropertiesSerializer, "Serializer should be custom not the default");
+ Assert.AreNotEqual(cosmosSerializer, serializer, "Serializer should be in the CosmosJsonSerializerWrapper");
+
+ CosmosJsonSerializerWrapper cosmosJsonSerializerWrapper = cosmosSerializer as CosmosJsonSerializerWrapper;
+ Assert.IsNotNull(cosmosJsonSerializerWrapper);
+ Assert.AreEqual(cosmosJsonSerializerWrapper.InternalJsonSerializer, serializer);
+ }
+
+ [TestMethod]
+ public void GetCosmosSerializerWithWrapperOrDefaultWithOptionsTest()
+ {
+ CosmosSerializationOptions serializerOptions = new CosmosSerializationOptions();
+ Assert.IsFalse(serializerOptions.IgnoreNullValues);
+ Assert.IsFalse(serializerOptions.Indented);
+ Assert.AreEqual(CosmosPropertyNamingPolicy.Default, serializerOptions.PropertyNamingPolicy);
+
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ SerializerOptions = new CosmosSerializationOptions()
+ {
+ IgnoreNullValues = true,
+ Indented = true,
+ PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
+ }
+ };
+
+ CosmosSerializer cosmosSerializer = options.GetCosmosSerializerWithWrapperOrDefault();
+ Assert.AreNotEqual(cosmosSerializer, options.PropertiesSerializer, "Serializer should be custom not the default");
+
+ CosmosJsonSerializerWrapper cosmosJsonSerializerWrapper = cosmosSerializer as CosmosJsonSerializerWrapper;
+ Assert.IsNotNull(cosmosJsonSerializerWrapper);
+
+ // Verify the custom settings are being honored
+ dynamic testItem = new { id = "testid", description = (string)null, CamelCaseProperty = "TestCamelCase" };
+ using (Stream stream = cosmosSerializer.ToStream(testItem))
+ {
+ using (StreamReader sr = new StreamReader(stream))
+ {
+ string jsonString = sr.ReadToEnd();
+ // Notice description is not included, camelCaseProperty starts lower case, the white space shows the indents
+ string expectedJsonString = "{\r\n \"id\": \"testid\",\r\n \"camelCaseProperty\": \"TestCamelCase\"\r\n}";
+ Assert.AreEqual(expectedJsonString, jsonString);
+ }
+ }
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void ThrowOnSerializerOptionsWithCustomSerializer()
+ {
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ Serializer = new CosmosJsonDotNetSerializer()
+ };
+
+ options.SerializerOptions = new CosmosSerializationOptions();
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void ThrowOnCustomSerializerWithSerializerOptions()
+ {
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ SerializerOptions = new CosmosSerializationOptions()
+ };
+
+ options.Serializer = new CosmosJsonDotNetSerializer();
+ }
+
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void ThrowOnNullConnectionString()
@@ -160,19 +250,19 @@ public void ThrowOnMissingAccountEndpointInConnectionString()
public void AssertJsonSerializer()
{
string connectionString = "AccountEndpoint=https://localtestcosmos.documents.azure.com:443/;AccountKey=425Mcv8CXQqzRNCgFNjIhT424GK99CKJvASowTnq15Vt8LeahXTcN5wt3342vQ==;";
- var cosmosClientBuilder = new CosmosClientBuilder(connectionString);
- var cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient());
- Assert.IsInstanceOfType(cosmosClient.ClientOptions.CosmosSerializerWithWrapperOrDefault, typeof(CosmosJsonSerializerWrapper));
- Assert.AreEqual(cosmosClient.ClientOptions.CosmosSerializerWithWrapperOrDefault, cosmosClient.ClientOptions.PropertiesSerializer);
+ CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(connectionString);
+ CosmosClient cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient());
+ Assert.IsInstanceOfType(cosmosClient.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), typeof(CosmosJsonSerializerWrapper));
+ Assert.AreEqual(cosmosClient.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), cosmosClient.ClientOptions.PropertiesSerializer);
CosmosSerializer defaultSerializer = cosmosClient.ClientOptions.PropertiesSerializer;
CosmosSerializer mockJsonSerializer = new Mock().Object;
cosmosClientBuilder.WithCustomSerializer(mockJsonSerializer);
- var cosmosClientCustom = cosmosClientBuilder.Build(new MockDocumentClient());
+ CosmosClient cosmosClientCustom = cosmosClientBuilder.Build(new MockDocumentClient());
Assert.AreEqual(defaultSerializer, cosmosClientCustom.ClientOptions.PropertiesSerializer);
Assert.AreEqual(mockJsonSerializer, cosmosClientCustom.ClientOptions.Serializer);
- Assert.IsInstanceOfType(cosmosClientCustom.ClientOptions.CosmosSerializerWithWrapperOrDefault, typeof(CosmosJsonSerializerWrapper));
- Assert.AreEqual(mockJsonSerializer, ((CosmosJsonSerializerWrapper)cosmosClientCustom.ClientOptions.CosmosSerializerWithWrapperOrDefault).InternalJsonSerializer);
+ Assert.IsInstanceOfType(cosmosClientCustom.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), typeof(CosmosJsonSerializerWrapper));
+ Assert.AreEqual(mockJsonSerializer, ((CosmosJsonSerializerWrapper)cosmosClientCustom.ClientOptions.GetCosmosSerializerWithWrapperOrDefault()).InternalJsonSerializer);
}
}
}
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 57b123c6dd..01cbe3d275 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
@@ -1246,11 +1246,19 @@
],
"MethodInfo": "Microsoft.Azure.Cosmos.ConnectionMode get_ConnectionMode()"
},
- "Microsoft.Azure.Cosmos.CosmosSerializer get_Serializer()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Microsoft.Azure.Cosmos.CosmosSerializationOptions get_SerializerOptions()": {
"Type": "Method",
- "Attributes": [
- "CompilerGeneratedAttribute"
- ],
+ "Attributes": [],
+ "MethodInfo": "Microsoft.Azure.Cosmos.CosmosSerializationOptions get_SerializerOptions()"
+ },
+ "Microsoft.Azure.Cosmos.CosmosSerializationOptions SerializerOptions": {
+ "Type": "Property",
+ "Attributes": [],
+ "MethodInfo": null
+ },
+ "Microsoft.Azure.Cosmos.CosmosSerializer get_Serializer()": {
+ "Type": "Method",
+ "Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.CosmosSerializer get_Serializer()"
},
"Microsoft.Azure.Cosmos.CosmosSerializer Serializer[Newtonsoft.Json.JsonConverterAttribute(typeof(Microsoft.Azure.Cosmos.CosmosClientOptions+ClientOptionJsonConverter))]": {
@@ -1267,9 +1275,11 @@
],
"MethodInfo": null
},
- "System.Collections.ObjectModel.Collection`1[Microsoft.Azure.Cosmos.RequestHandler] get_CustomHandlers()": {
+ "System.Collections.ObjectModel.Collection`1[Microsoft.Azure.Cosmos.RequestHandler] get_CustomHandlers()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
- "Attributes": [],
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
"MethodInfo": "System.Collections.ObjectModel.Collection`1[Microsoft.Azure.Cosmos.RequestHandler] get_CustomHandlers()"
},
"System.Nullable`1[Microsoft.Azure.Cosmos.ConsistencyLevel] ConsistencyLevel": {
@@ -1399,12 +1409,15 @@
],
"MethodInfo": "Void set_RequestTimeout(System.TimeSpan)"
},
- "Void set_Serializer(Microsoft.Azure.Cosmos.CosmosSerializer)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Void set_Serializer(Microsoft.Azure.Cosmos.CosmosSerializer)": {
"Type": "Method",
- "Attributes": [
- "CompilerGeneratedAttribute"
- ],
+ "Attributes": [],
"MethodInfo": "Void set_Serializer(Microsoft.Azure.Cosmos.CosmosSerializer)"
+ },
+ "Void set_SerializerOptions(Microsoft.Azure.Cosmos.CosmosSerializationOptions)": {
+ "Type": "Method",
+ "Attributes": [],
+ "MethodInfo": "Void set_SerializerOptions(Microsoft.Azure.Cosmos.CosmosSerializationOptions)"
}
},
"NestedTypes": {}
@@ -1514,51 +1527,97 @@
},
"NestedTypes": {}
},
- "CosmosJsonDotNetSerializer": {
+ "CosmosPropertyNamingPolicy": {
"Subclasses": {},
"Members": {
- "System.IO.Stream ToStream[T](T)": {
+ "Int32 value__": {
+ "Type": "Field",
+ "Attributes": [],
+ "MethodInfo": null
+ },
+ "Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy CamelCase": {
+ "Type": "Field",
+ "Attributes": [],
+ "MethodInfo": null
+ },
+ "Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy Default": {
+ "Type": "Field",
+ "Attributes": [],
+ "MethodInfo": null
+ }
+ },
+ "NestedTypes": {}
+ },
+ "CosmosSerializationOptions": {
+ "Subclasses": {},
+ "Members": {
+ "Boolean get_IgnoreNullValues()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Boolean get_IgnoreNullValues()"
+ },
+ "Boolean get_Indented()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Boolean get_Indented()"
+ },
+ "Boolean IgnoreNullValues": {
+ "Type": "Property",
"Attributes": [],
- "MethodInfo": "System.IO.Stream ToStream[T](T)"
+ "MethodInfo": null
},
- "T FromStream[T](System.IO.Stream)": {
+ "Boolean Indented": {
+ "Type": "Property",
+ "Attributes": [],
+ "MethodInfo": null
+ },
+ "Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy get_PropertyNamingPolicy()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy get_PropertyNamingPolicy()"
+ },
+ "Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy PropertyNamingPolicy": {
+ "Type": "Property",
"Attributes": [],
- "MethodInfo": "T FromStream[T](System.IO.Stream)"
+ "MethodInfo": null
},
- "Void .ctor(Newtonsoft.Json.JsonSerializerSettings)": {
+ "Void .ctor()": {
"Type": "Constructor",
"Attributes": [],
- "MethodInfo": "Void .ctor(Newtonsoft.Json.JsonSerializerSettings)"
+ "MethodInfo": "Void .ctor()"
+ },
+ "Void set_IgnoreNullValues(Boolean)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Void set_IgnoreNullValues(Boolean)"
+ },
+ "Void set_Indented(Boolean)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Void set_Indented(Boolean)"
+ },
+ "Void set_PropertyNamingPolicy(Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
+ "Type": "Method",
+ "Attributes": [
+ "CompilerGeneratedAttribute"
+ ],
+ "MethodInfo": "Void set_PropertyNamingPolicy(Microsoft.Azure.Cosmos.CosmosPropertyNamingPolicy)"
}
},
"NestedTypes": {}
},
"CosmosSerializer": {
- "Subclasses": {
- "CosmosJsonDotNetSerializer": {
- "Subclasses": {},
- "Members": {
- "System.IO.Stream ToStream[T](T)": {
- "Type": "Method",
- "Attributes": [],
- "MethodInfo": "System.IO.Stream ToStream[T](T)"
- },
- "T FromStream[T](System.IO.Stream)": {
- "Type": "Method",
- "Attributes": [],
- "MethodInfo": "T FromStream[T](System.IO.Stream)"
- },
- "Void .ctor(Newtonsoft.Json.JsonSerializerSettings)": {
- "Type": "Constructor",
- "Attributes": [],
- "MethodInfo": "Void .ctor(Newtonsoft.Json.JsonSerializerSettings)"
- }
- },
- "NestedTypes": {}
- }
- },
+ "Subclasses": {},
"Members": {
"System.IO.Stream ToStream[T](T)": {
"Type": "Method",
@@ -2167,6 +2226,11 @@
"Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithRequestTimeout(System.TimeSpan)"
},
+ "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithSerializerOptions(Microsoft.Azure.Cosmos.CosmosSerializationOptions)": {
+ "Type": "Method",
+ "Attributes": [],
+ "MethodInfo": "Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithSerializerOptions(Microsoft.Azure.Cosmos.CosmosSerializationOptions)"
+ },
"Microsoft.Azure.Cosmos.Fluent.CosmosClientBuilder WithThrottlingRetryOptions(System.TimeSpan, Int32)": {
"Type": "Method",
"Attributes": [],
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/LocationCacheTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/LocationCacheTests.cs
index 500a61a076..afda45e375 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/LocationCacheTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/LocationCacheTests.cs
@@ -506,12 +506,20 @@ await BackoffRetryUtility.ExecuteAsync(
[Owner("atulk")]
public async Task ValidateAsync()
{
- for (int i = 0; i < 8; i++)
+ bool[] boolValues = new bool[] {true, false};
+
+ foreach (bool useMultipleWriteEndpoints in boolValues)
{
- bool useMultipleWriteEndpoints = (i & 1) > 0;
- bool endpointDiscoveryEnabled = (i & 2) > 0;
- bool isPreferredListEmpty = (i & 4) > 0;
- await this.ValidateLocationCacheAsync(useMultipleWriteEndpoints, endpointDiscoveryEnabled, isPreferredListEmpty);
+ foreach (bool endpointDiscoveryEnabled in boolValues)
+ {
+ foreach (bool isPreferredListEmpty in boolValues)
+ {
+ await this.ValidateLocationCacheAsync(
+ useMultipleWriteEndpoints,
+ endpointDiscoveryEnabled,
+ isPreferredListEmpty);
+ }
+ }
}
}
@@ -642,15 +650,34 @@ private async Task ValidateLocationCacheAsync(
preferredAvailableWriteEndpoints,
preferredAvailableReadEndpoints);
- // wait for TTL on unavailablity info
- await Task.Delay(
- int.Parse(
- System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"],
- NumberStyles.Integer,
- CultureInfo.InvariantCulture) * 1000);
-
- CollectionAssert.AreEqual(currentWriteEndpoints, this.cache.WriteEndpoints);
- CollectionAssert.AreEqual(currentReadEndpoints, this.cache.ReadEndpoints);
+ // wait for TTL on unavailability info
+ string expirationTime = System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"];
+ int delayInMilliSeconds = int.Parse(
+ expirationTime,
+ NumberStyles.Integer,
+ CultureInfo.InvariantCulture) * 1000;
+ await Task.Delay(delayInMilliSeconds);
+
+ string config = $"Delay{expirationTime};" +
+ $"useMultipleWriteLocations:{useMultipleWriteLocations};" +
+ $"endpointDiscoveryEnabled:{endpointDiscoveryEnabled};" +
+ $"isPreferredListEmpty:{isPreferredListEmpty}";
+
+ CollectionAssert.AreEqual(
+ currentWriteEndpoints,
+ this.cache.WriteEndpoints,
+ "Write Endpoints failed;" +
+ $"config:{config};" +
+ $"Current:{string.Join(",", currentWriteEndpoints)};" +
+ $"Cache:{string.Join(",", this.cache.WriteEndpoints)};");
+
+ CollectionAssert.AreEqual(
+ currentReadEndpoints,
+ this.cache.ReadEndpoints,
+ "Read Endpoints failed;" +
+ $"config:{config};" +
+ $"Current:{string.Join(",", currentReadEndpoints)};" +
+ $"Cache:{string.Join(",", this.cache.ReadEndpoints)};");
}
}
}
diff --git a/changelog.md b/changelog.md
index b82e187cd1..e602e25936 100644
--- a/changelog.md
+++ b/changelog.md
@@ -5,6 +5,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- [#650](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/650) CosmosSerializerOptions to customize serialization
+
### Fixed
- [#612](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/612) Bug fix for ReadFeed with partition-key
@@ -20,7 +24,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#541](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/541) Added consistency level to client and query options
- [#544](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/544) Added continuation token support for LINQ
- [#557](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/557) Added trigger options to item request options
-- [#571](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/571) Added a default JSON.net serializer with optional settings
- [#572](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/572) Added partition key validation on CreateContainerIfNotExistsAsync
- [#581](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/581) Added LINQ to QueryDefinition API
- [#592](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/592) Added CreateIfNotExistsAsync to container builder