diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index c826bb90d1..e4b948dd1e 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -72,6 +72,8 @@ public class CosmosClientOptions private IWebProxy webProxy; private Func httpClientFactory; private string applicationName; + private string applicationRegion; + private IReadOnlyList applicationPreferredRegions; /// /// Creates a new CosmosClientOptions @@ -154,7 +156,11 @@ public string ApplicationName /// /// /// High availability on regional outages - public string ApplicationRegion { get; set; } + public string ApplicationRegion + { + get => this.applicationRegion; + set => this.applicationRegion = RegionNameMapping.GetCosmosDBRegionName(value); + } /// /// Gets and sets the preferred regions for geo-replicated database accounts in the Azure Cosmos DB service. @@ -189,7 +195,11 @@ public string ApplicationName /// /// /// High availability on regional outages - public IReadOnlyList ApplicationPreferredRegions { get; set; } + public IReadOnlyList ApplicationPreferredRegions + { + get => this.applicationPreferredRegions; + set => this.applicationPreferredRegions = value?.Select(RegionNameMapping.GetCosmosDBRegionName).ToList(); + } /// /// Get or set the maximum number of concurrent connections allowed for the target diff --git a/Microsoft.Azure.Cosmos/src/RegionNameMapping.cs b/Microsoft.Azure.Cosmos/src/RegionNameMapping.cs new file mode 100644 index 0000000000..d8d18149f0 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/RegionNameMapping.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Maps a normalized region name to the format that CosmosDB is expecting (for e.g. from 'westus2' to 'West US 2') + /// + internal class RegionNameMapping + { + private static readonly IDictionary normalizedToCosmosDBRegionNameMapping; + + static RegionNameMapping() + { + FieldInfo[] fields = typeof(Regions).GetFields(BindingFlags.Public | BindingFlags.Static); + normalizedToCosmosDBRegionNameMapping = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (FieldInfo field in fields) + { + normalizedToCosmosDBRegionNameMapping[field.Name.ToLowerInvariant()] = field.GetValue(null).ToString(); + } + } + + /// + /// Given a normalized region name, this function retrieves the region name in the format that CosmosDB expects. + /// If the region is not known, the same value as input is returned. + /// + /// An Azure region name in a normalized format. The input is not case sensitive. + /// A string that contains the region name in the format that CosmosDB expects. + public static string GetCosmosDBRegionName(string normalizedRegionName) + { + if (normalizedRegionName != null && normalizedToCosmosDBRegionNameMapping.TryGetValue(normalizedRegionName, out string cosmosDBRegionName)) + { + return cosmosDBRegionName; + } + + return normalizedRegionName; + } + } +} 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 efb06d7cc5..13528ce380 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs @@ -539,6 +539,74 @@ public void WithQuorumReadWithEventualConsistencyAccount() Assert.IsTrue(cosmosClientOptions.EnableUpgradeConsistencyToLocalQuorum); } + [TestMethod] + public void VerifyRegionNameFormatConversionForApplicationRegion() + { + CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); + cosmosClientOptions.ApplicationRegion = "westus2"; + Assert.AreEqual(Regions.WestUS2, cosmosClientOptions.ApplicationRegion); + } + + [TestMethod] + public void VerifyRegionNameFormatConversionBypassForApplicationRegion() + { + CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); + + // No conversion for expected format. + cosmosClientOptions.ApplicationRegion = Regions.AustraliaCentral2; + Assert.AreEqual(Regions.AustraliaCentral2, cosmosClientOptions.ApplicationRegion); + + // Ignore unknown values. + cosmosClientOptions.ApplicationRegion = null; + Assert.IsNull(cosmosClientOptions.ApplicationRegion); + + cosmosClientOptions.ApplicationRegion = string.Empty; + Assert.AreEqual(string.Empty, cosmosClientOptions.ApplicationRegion); + + cosmosClientOptions.ApplicationRegion = "Invalid region"; + Assert.AreEqual("Invalid region", cosmosClientOptions.ApplicationRegion); + } + + [TestMethod] + public void VerifyRegionNameFormatConversionForApplicationPreferredRegions() + { + CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); + cosmosClientOptions.ApplicationPreferredRegions = new List {"westus2", "usdodcentral", Regions.ChinaNorth3}; + Assert.AreEqual(Regions.WestUS2, cosmosClientOptions.ApplicationPreferredRegions[0]); + Assert.AreEqual(Regions.USDoDCentral, cosmosClientOptions.ApplicationPreferredRegions[1]); + Assert.AreEqual(Regions.ChinaNorth3, cosmosClientOptions.ApplicationPreferredRegions[2]); + } + + [TestMethod] + public void VerifyRegionNameFormatConversionBypassForInvalidApplicationPreferredRegions() + { + CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); + + // List is null + cosmosClientOptions.ApplicationPreferredRegions = null; + Assert.IsNull(cosmosClientOptions.ApplicationRegion); + + // List is empty + cosmosClientOptions.ApplicationPreferredRegions = new List(); + Assert.AreEqual(0, cosmosClientOptions.ApplicationPreferredRegions.Count); + + // List contains valid and invalid values + cosmosClientOptions.ApplicationPreferredRegions = new List + { + null, + string.Empty, + Regions.JioIndiaCentral, + "westus2", + "Invalid region" + }; + + Assert.IsNull(cosmosClientOptions.ApplicationPreferredRegions[0]); + Assert.AreEqual(string.Empty, cosmosClientOptions.ApplicationPreferredRegions[1]); + Assert.AreEqual(Regions.JioIndiaCentral, cosmosClientOptions.ApplicationPreferredRegions[2]); + Assert.AreEqual(Regions.WestUS2, cosmosClientOptions.ApplicationPreferredRegions[3]); + Assert.AreEqual("Invalid region", cosmosClientOptions.ApplicationPreferredRegions[4]); + } + [TestMethod] public void InvalidApplicationNameCatchTest() {