Skip to content

Commit e859ae7

Browse files
authored
Cosmos: Add a way to configure Application Preferred Regions
Fixes #29424
1 parent 11512f5 commit e859ae7

File tree

6 files changed

+63
-0
lines changed

6 files changed

+63
-0
lines changed

src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ public virtual CosmosDbContextOptionsBuilder ExecutionStrategy(
6565
public virtual CosmosDbContextOptionsBuilder Region(string region)
6666
=> WithOption(e => e.WithRegion(Check.NotNull(region, nameof(region))));
6767

68+
/// <summary>
69+
/// Configures the context to use the provided preferred regions for geo-replicated database accounts.
70+
/// </summary>
71+
/// <remarks>
72+
/// See <see href="https://aka.ms/efcore-docs-dbcontext-options">Using DbContextOptions</see>, and
73+
/// <see href="https://aka.ms/efcore-docs-cosmos">Accessing Azure Cosmos DB with EF Core</see> for more information and examples.
74+
/// </remarks>
75+
/// <param name="regions">A list of Azure Cosmos DB region names.</param>
76+
public virtual CosmosDbContextOptionsBuilder PreferredRegions(IReadOnlyList<string> regions)
77+
=> WithOption(e => e.WithPreferredRegions(Check.NotNull(regions, nameof(regions))));
78+
6879
/// <summary>
6980
/// Limits the operations to the provided endpoint.
7081
/// </summary>

src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class CosmosOptionsExtension : IDbContextOptionsExtension
2323
private string? _connectionString;
2424
private string? _databaseName;
2525
private string? _region;
26+
private IReadOnlyList<string>? _preferredRegions;
2627
private ConnectionMode? _connectionMode;
2728
private bool? _limitToEndpoint;
2829
private Func<ExecutionStrategyDependencies, IExecutionStrategy>? _executionStrategyFactory;
@@ -61,6 +62,7 @@ protected CosmosOptionsExtension(CosmosOptionsExtension copyFrom)
6162
_databaseName = copyFrom._databaseName;
6263
_connectionString = copyFrom._connectionString;
6364
_region = copyFrom._region;
65+
_preferredRegions = copyFrom._preferredRegions;
6466
_connectionMode = copyFrom._connectionMode;
6567
_limitToEndpoint = copyFrom._limitToEndpoint;
6668
_executionStrategyFactory = copyFrom._executionStrategyFactory;
@@ -247,6 +249,30 @@ public virtual CosmosOptionsExtension WithRegion(string? region)
247249
return clone;
248250
}
249251

252+
/// <summary>
253+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
254+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
255+
/// any release. You should only use it directly in your code with extreme caution and knowing that
256+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
257+
/// </summary>
258+
public virtual IReadOnlyList<string>? PreferredRegions
259+
=> _preferredRegions;
260+
261+
/// <summary>
262+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
263+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
264+
/// any release. You should only use it directly in your code with extreme caution and knowing that
265+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
266+
/// </summary>
267+
public virtual CosmosOptionsExtension WithPreferredRegions(IReadOnlyList<string>? regions)
268+
{
269+
var clone = Clone();
270+
271+
clone._preferredRegions = regions;
272+
273+
return clone;
274+
}
275+
250276
/// <summary>
251277
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
252278
/// the same compatibility standards as public APIs. It may be changed or removed without notice in

src/EFCore.Cosmos/Infrastructure/Internal/CosmosSingletonOptions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections;
45
using System.Net;
56
using Azure.Core;
67

@@ -54,6 +55,14 @@ public class CosmosSingletonOptions : ICosmosSingletonOptions
5455
/// </summary>
5556
public virtual string? Region { get; private set; }
5657

58+
/// <summary>
59+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
60+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
61+
/// any release. You should only use it directly in your code with extreme caution and knowing that
62+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
63+
/// </summary>
64+
public virtual IReadOnlyList<string>? PreferredRegions { get; private set; }
65+
5766
/// <summary>
5867
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
5968
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -158,6 +167,7 @@ public virtual void Initialize(IDbContextOptions options)
158167
TokenCredential = cosmosOptions.TokenCredential;
159168
ConnectionString = cosmosOptions.ConnectionString;
160169
Region = cosmosOptions.Region;
170+
PreferredRegions = cosmosOptions.PreferredRegions;
161171
LimitToEndpoint = cosmosOptions.LimitToEndpoint;
162172
EnableContentResponseOnWrite = cosmosOptions.EnableContentResponseOnWrite;
163173
ConnectionMode = cosmosOptions.ConnectionMode;
@@ -188,6 +198,7 @@ public virtual void Validate(IDbContextOptions options)
188198
|| TokenCredential != cosmosOptions.TokenCredential
189199
|| ConnectionString != cosmosOptions.ConnectionString
190200
|| Region != cosmosOptions.Region
201+
|| !StructuralComparisons.StructuralEqualityComparer.Equals(PreferredRegions, cosmosOptions.PreferredRegions)
191202
|| LimitToEndpoint != cosmosOptions.LimitToEndpoint
192203
|| ConnectionMode != cosmosOptions.ConnectionMode
193204
|| WebProxy != cosmosOptions.WebProxy

src/EFCore.Cosmos/Infrastructure/Internal/ICosmosSingletonOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ public interface ICosmosSingletonOptions : ISingletonOptions
6060
/// </summary>
6161
string? Region { get; }
6262

63+
/// <summary>
64+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
65+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
66+
/// any release. You should only use it directly in your code with extreme caution and knowing that
67+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
68+
/// </summary>
69+
IReadOnlyList<string>? PreferredRegions { get; }
70+
6371
/// <summary>
6472
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
6573
/// the same compatibility standards as public APIs. It may be changed or removed without notice in

src/EFCore.Cosmos/Storage/Internal/SingletonCosmosClientWrapper.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ public SingletonCosmosClientWrapper(ICosmosSingletonOptions options)
4141
configuration.ApplicationRegion = options.Region;
4242
}
4343

44+
if (options.PreferredRegions != null)
45+
{
46+
configuration.ApplicationPreferredRegions = options.PreferredRegions;
47+
}
48+
4449
if (options.LimitToEndpoint != null)
4550
{
4651
configuration.LimitToEndpoint = options.LimitToEndpoint.Value;

test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public void Can_create_options_with_valid_values()
7171
Test(o => o.Region(Regions.EastAsia), o => Assert.Equal(Regions.EastAsia, o.Region));
7272
// The region will be validated by the Cosmos SDK, because the region list is not constant
7373
Test(o => o.Region("FakeRegion"), o => Assert.Equal("FakeRegion", o.Region));
74+
Test(o => o.PreferredRegions(new[] { Regions.AustraliaCentral, Regions.EastAsia }),
75+
o => Assert.Equal(new[] { Regions.AustraliaCentral, Regions.EastAsia }, o.PreferredRegions));
7476
Test(o => o.ConnectionMode(ConnectionMode.Direct), o => Assert.Equal(ConnectionMode.Direct, o.ConnectionMode));
7577
Test(o => o.GatewayModeMaxConnectionLimit(3), o => Assert.Equal(3, o.GatewayModeMaxConnectionLimit));
7678
Test(o => o.MaxRequestsPerTcpConnection(3), o => Assert.Equal(3, o.MaxRequestsPerTcpConnection));

0 commit comments

Comments
 (0)