Skip to content

Commit a51a674

Browse files
Add support ConfigurationManager in Net Standard for configurable retry logic (#1090)
1 parent b672ea7 commit a51a674

18 files changed

+108
-171
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@
310310
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs">
311311
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs</Link>
312312
</Compile>
313+
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs">
314+
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs</Link>
315+
</Compile>
316+
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs">
317+
<Link>Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs</Link>
318+
</Compile>
319+
<Compile Include="Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.NetCoreApp.cs" />
320+
<Compile Include="Microsoft\Data\SqlClient\SqlAppContextSwitchManager.NetCoreApp.cs" />
313321
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlUtil.cs">
314322
<Link>Microsoft\Data\SqlClient\SqlUtil.cs</Link>
315323
</Compile>
@@ -334,7 +342,6 @@
334342
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetStandard.cs" />
335343
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetStandard.cs" />
336344
<Compile Include="Microsoft\Data\SqlClient\SNI\SslOverTdsStream.NetStandard.cs" />
337-
<Compile Include="Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.NetStandard.cs" />
338345
</ItemGroup>
339346
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetFramework)' != 'netstandard2.0'">
340347
<Compile Include="..\..\src\Microsoft\Data\SqlClient\AlwaysEncryptedAttestationException.cs">
@@ -383,14 +390,6 @@
383390
<Compile Include="Microsoft\Data\SqlClient\SNI\SslOverTdsStream.NetCoreApp.cs" />
384391
<Compile Include="Microsoft\Data\SqlClient\SqlConnectionFactory.AssemblyLoadContext.cs" />
385392
<Compile Include="Microsoft\Data\SqlClient\SqlDependencyUtils.AssemblyLoadContext.cs" />
386-
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.CreateProvider.cs">
387-
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.CreateProvider.NetCoreApp.cs</Link>
388-
</Compile>
389-
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs">
390-
<Link>Microsoft\Data\SqlClient\Reliability\AppConfigManager.NetCoreApp.cs</Link>
391-
</Compile>
392-
<Compile Include="Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.NetCoreApp.cs" />
393-
<Compile Include="Microsoft\Data\SqlClient\Reliability\SqlAppContextSwitchManager.NetCoreApp.cs" />
394393
</ItemGroup>
395394
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetFramework)' != 'netstandard2.0' AND '$(BuildSimulator)' == 'true'">
396395
<Compile Include="Microsoft\Data\SqlClient\SimulatorEnclaveProvider.NetCoreApp.cs" />
@@ -838,7 +837,7 @@
838837
</ItemGroup>
839838
<ItemGroup>
840839
<PackageReference Condition="'$(TargetsWindows)' == 'true' and '$(IsUAPAssembly)' != 'true'" Include="Microsoft.Win32.Registry" Version="$(MicrosoftWin32RegistryVersion)" />
841-
<PackageReference Condition="'$(TargetGroup)' == 'netcoreapp'" Include="System.Configuration.ConfigurationManager" Version="$(SystemConfigurationConfigurationManagerVersion)" />
840+
<PackageReference Include="System.Configuration.ConfigurationManager" Version="$(SystemConfigurationConfigurationManagerVersion)" />
842841
<PackageReference Include="System.Security.Permissions" Version="$(SystemSecurityPermissionsVersion)" />
843842
<PackageReference Include="System.Security.Principal.Windows" Version="$(SystemSecurityPrincipalWindowsVersion)" />
844843
<PackageReference Include="System.Text.Encoding.CodePages" Version="$(SystemTextEncodingCodePagesVersion)" />
@@ -857,6 +856,7 @@
857856
<PackageReference Include="System.Resources.ResourceManager" Version="$(SystemResourcesResourceManagerVersion)" />
858857
<PackageReference Include="System.Buffers" Version="$(SystemBuffersVersion)" />
859858
<PackageReference Include="System.Runtime.Caching" Version="$(SystemRuntimeCachingVersion)" />
859+
<PackageReference Condition="$(TargetGroup) == 'netstandard'" Include="System.Runtime.Loader" Version="$(SystemRuntimeLoaderVersion)" />
860860
<PackageReference Include="System.Security.Cryptography.Cng" Version="$(SystemSecurityCryptographyCngVersion)" />
861861
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(MicrosoftSourceLinkGitHubVersion)" PrivateAssets="All" />
862862
</ItemGroup>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicManager.NetStandard.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -493,20 +493,7 @@ private SqlInternalConnectionTds InternalTdsConnection
493493
}
494494
}
495495

496-
private bool? _isRetryEnabled;
497-
private bool IsRetryEnabled
498-
{
499-
get
500-
{
501-
if (_isRetryEnabled == null)
502-
{
503-
bool result;
504-
result = AppContext.TryGetSwitch(SqlRetryLogicProvider.EnableRetryLogicSwitch, out result) ? result : false;
505-
_isRetryEnabled = result;
506-
}
507-
return (bool)_isRetryEnabled;
508-
}
509-
}
496+
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
510497

511498
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/RetryLogicProvider/*' />
512499
public SqlRetryLogicBaseProvider RetryLogicProvider

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,7 @@ private static readonly ConcurrentDictionary<string, IList<string>> _ColumnEncry
111111
private static readonly Action<object> s_openAsyncCancel = OpenAsyncCancel;
112112
private static readonly Action<Task<object>, object> s_openAsyncComplete = OpenAsyncComplete;
113113

114-
private bool? _isRetryEnabled;
115-
private bool IsRetryEnabled
116-
{
117-
get
118-
{
119-
if (_isRetryEnabled == null)
120-
{
121-
bool result;
122-
result = AppContext.TryGetSwitch(SqlRetryLogicProvider.EnableRetryLogicSwitch, out result) ? result : false;
123-
_isRetryEnabled = result;
124-
}
125-
return (bool)_isRetryEnabled;
126-
}
127-
}
114+
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
128115

129116
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/RetryLogicProvider/*' />
130117
public SqlRetryLogicBaseProvider RetryLogicProvider

src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,8 @@
401401
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs">
402402
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs</Link>
403403
</Compile>
404-
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.CreateProvider.cs">
405-
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.CreateProvider.cs</Link>
404+
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs">
405+
<Link>Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs</Link>
406406
</Compile>
407407
<Compile Include="..\..\src\Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs">
408408
<Link>Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs</Link>

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -616,20 +616,7 @@ private bool IsShiloh
616616
}
617617
}
618618

619-
private bool? _isRetryEnabled;
620-
private bool IsRetryEnabled
621-
{
622-
get
623-
{
624-
if (_isRetryEnabled == null)
625-
{
626-
bool result;
627-
result = AppContext.TryGetSwitch(SqlRetryLogicProvider.EnableRetryLogicSwitch, out result) ? result : false;
628-
_isRetryEnabled = result;
629-
}
630-
return (bool)_isRetryEnabled;
631-
}
632-
}
619+
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
633620

634621
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/RetryLogicProvider/*' />
635622
[

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -310,20 +310,7 @@ internal List<string> GetColumnEncryptionCustomKeyStoreProvidersNames()
310310

311311
// Retry Logic
312312
private SqlRetryLogicBaseProvider _retryLogicProvider;
313-
private bool? _isRetryEnabled;
314-
private bool IsRetryEnabled
315-
{
316-
get
317-
{
318-
if (_isRetryEnabled == null)
319-
{
320-
bool result;
321-
result = AppContext.TryGetSwitch(SqlRetryLogicProvider.EnableRetryLogicSwitch, out result) ? result : false;
322-
_isRetryEnabled = result;
323-
}
324-
return (bool)_isRetryEnabled;
325-
}
326-
}
313+
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
327314

328315
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/RetryLogicProvider/*' />
329316
[

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,52 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Reflection;
67
using System.Runtime.CompilerServices;
78

89
namespace Microsoft.Data.SqlClient
910
{
1011
internal static partial class LocalAppContextSwitches
1112
{
13+
private const string TypeName = nameof(LocalAppContextSwitches);
1214
internal const string MakeReadAsyncBlockingString = @"Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking";
1315
internal const string LegacyRowVersionNullString = @"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior";
16+
// safety switch
17+
internal const string EnableRetryLogicSwitch = "Switch.Microsoft.Data.SqlClient.EnableRetryLogic";
1418

1519
private static bool _makeReadAsyncBlocking;
1620
private static bool? s_LegacyRowVersionNullBehavior;
21+
private static bool? s_isRetryEnabled = null;
22+
23+
#if !NETFRAMEWORK
24+
static LocalAppContextSwitches()
25+
{
26+
IAppContextSwitchOverridesSection appContextSwitch = AppConfigManager.FetchConfigurationSection<AppContextSwitchOverridesSection>(AppContextSwitchOverridesSection.Name);
27+
try
28+
{
29+
SqlAppContextSwitchManager.ApplyContextSwitches(appContextSwitch);
30+
}
31+
catch (Exception e)
32+
{
33+
// Don't throw an exception for an invalid config file
34+
SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO>: {2}", TypeName, MethodBase.GetCurrentMethod().Name, e);
35+
}
36+
}
37+
#endif
38+
39+
internal static bool IsRetryEnabled
40+
{
41+
get
42+
{
43+
if (s_isRetryEnabled is null)
44+
{
45+
bool result;
46+
result = AppContext.TryGetSwitch(EnableRetryLogicSwitch, out result) ? result : false;
47+
s_isRetryEnabled = result;
48+
}
49+
return s_isRetryEnabled.Value;
50+
}
51+
}
1752

1853
public static bool MakeReadAsyncBlocking
1954
{
@@ -33,7 +68,7 @@ public static bool LegacyRowVersionNullBehavior
3368
{
3469
get
3570
{
36-
if (s_LegacyRowVersionNullBehavior == null)
71+
if (s_LegacyRowVersionNullBehavior is null)
3772
{
3873
bool value = false;
3974
if (AppContext.TryGetSwitch(LegacyRowVersionNullString, out bool providedValue))

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/Common/SqlRetryLogicProvider.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ internal class SqlRetryLogicProvider : SqlRetryLogicBaseProvider
1919
// keeps free RetryLogic objects
2020
private readonly ConcurrentBag<SqlRetryLogicBase> _retryLogicPool = new ConcurrentBag<SqlRetryLogicBase>();
2121

22-
// safety switch for the preview version
23-
internal const string EnableRetryLogicSwitch = "Switch.Microsoft.Data.SqlClient.EnableRetryLogic";
24-
2522
/// <summary>Creates an instance of this type.</summary>
2623
public SqlRetryLogicProvider(SqlRetryLogicBase retryLogic)
2724
{
Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,34 @@
99

1010
namespace Microsoft.Data.SqlClient
1111
{
12-
/// <summary>
13-
/// Configurable retry logic manager;
14-
/// Receive the default providers by a loader and feeds the connections and commands.
15-
/// </summary>
16-
internal sealed partial class SqlConfigurableRetryLogicManager
17-
{
18-
private static readonly Lazy<SqlConfigurableRetryLogicLoader> s_loader =
19-
new Lazy<SqlConfigurableRetryLogicLoader>(() =>
20-
{
21-
ISqlConfigurableRetryConnectionSection cnnConfig = null;
22-
ISqlConfigurableRetryCommandSection cmdConfig = null;
23-
24-
// Fetch the section attributes values from the configuration section of the app config file.
25-
cnnConfig = AppConfigManager.FetchConfigurationSection<SqlConfigurableRetryConnectionSection>(SqlConfigurableRetryConnectionSection.Name);
26-
cmdConfig = AppConfigManager.FetchConfigurationSection<SqlConfigurableRetryCommandSection>(SqlConfigurableRetryCommandSection.Name);
27-
#if !NETFRAMEWORK
28-
IAppContextSwitchOverridesSection appContextSwitch = AppConfigManager.FetchConfigurationSection<AppContextSwitchOverridesSection>(AppContextSwitchOverridesSection.Name);
29-
try
30-
{
31-
SqlAppContextSwitchManager.ApplyContextSwitches(appContextSwitch);
32-
}
33-
catch (Exception e)
34-
{
35-
// Don't throw an exception for an invalid config file
36-
SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO>: {2}", TypeName, MethodBase.GetCurrentMethod().Name, e);
37-
}
38-
#endif
39-
return new SqlConfigurableRetryLogicLoader(cnnConfig, cmdConfig);
40-
});
41-
}
42-
4312
/// <summary>
4413
/// Configurable retry logic loader
4514
/// This class shouldn't throw exceptions;
4615
/// All exceptions should be handled internally and logged with Event Source.
4716
/// </summary>
4817
internal sealed partial class SqlConfigurableRetryLogicLoader
4918
{
19+
private const string TypeName = nameof(SqlConfigurableRetryLogicLoader);
20+
21+
/// <summary>
22+
/// The default non retry provider will apply if a parameter passes by null.
23+
/// </summary>
24+
private void AssignProviders(SqlRetryLogicBaseProvider cnnProvider = null, SqlRetryLogicBaseProvider cmdProvider = null)
25+
{
26+
ConnectionProvider = cnnProvider ?? SqlConfigurableRetryFactory.CreateNoneRetryProvider();
27+
CommandProvider = cmdProvider ?? SqlConfigurableRetryFactory.CreateNoneRetryProvider();
28+
}
29+
30+
/// <summary>
31+
/// Default Retry provider for SqlConnections
32+
/// </summary>
33+
internal SqlRetryLogicBaseProvider ConnectionProvider { get; private set; }
34+
35+
/// <summary>
36+
/// Default Retry provider for SqlCommands
37+
/// </summary>
38+
internal SqlRetryLogicBaseProvider CommandProvider { get; private set; }
39+
5040
public SqlConfigurableRetryLogicLoader(ISqlConfigurableRetryConnectionSection connectionRetryConfigs,
5141
ISqlConfigurableRetryCommandSection commandRetryConfigs,
5242
string cnnSectionName = SqlConfigurableRetryConnectionSection.Name,

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicManager.cs

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,23 @@ namespace Microsoft.Data.SqlClient
1111
/// Configurable retry logic manager;
1212
/// Receive the default providers by a loader and feeds connections and commands.
1313
/// </summary>
14-
internal sealed partial class SqlConfigurableRetryLogicManager
14+
internal sealed class SqlConfigurableRetryLogicManager
1515
{
1616
private const string TypeName = nameof(SqlConfigurableRetryLogicManager);
1717

18+
private static readonly Lazy<SqlConfigurableRetryLogicLoader> s_loader =
19+
new Lazy<SqlConfigurableRetryLogicLoader>(() =>
20+
{
21+
ISqlConfigurableRetryConnectionSection cnnConfig = null;
22+
ISqlConfigurableRetryCommandSection cmdConfig = null;
23+
24+
// Fetch the section attributes values from the configuration section of the app config file.
25+
cnnConfig = AppConfigManager.FetchConfigurationSection<SqlConfigurableRetryConnectionSection>(SqlConfigurableRetryConnectionSection.Name);
26+
cmdConfig = AppConfigManager.FetchConfigurationSection<SqlConfigurableRetryCommandSection>(SqlConfigurableRetryCommandSection.Name);
27+
28+
return new SqlConfigurableRetryLogicLoader(cnnConfig, cmdConfig);
29+
});
30+
1831
private SqlConfigurableRetryLogicManager() {/*prevent external object creation*/}
1932

2033
/// <summary>
@@ -75,33 +88,6 @@ internal static SqlRetryLogicBaseProvider CommandProvider
7588

7689
}
7790

78-
/// <summary>
79-
/// Configurable retry logic loader
80-
/// </summary>
81-
internal sealed partial class SqlConfigurableRetryLogicLoader
82-
{
83-
private const string TypeName = nameof(SqlConfigurableRetryLogicLoader);
84-
85-
/// <summary>
86-
/// The default non retry provider will apply if a parameter passes by null.
87-
/// </summary>
88-
private void AssignProviders(SqlRetryLogicBaseProvider cnnProvider = null, SqlRetryLogicBaseProvider cmdProvider = null)
89-
{
90-
ConnectionProvider = cnnProvider ?? SqlConfigurableRetryFactory.CreateNoneRetryProvider();
91-
CommandProvider = cmdProvider ?? SqlConfigurableRetryFactory.CreateNoneRetryProvider();
92-
}
93-
94-
/// <summary>
95-
/// Default Retry provider for SqlConnections
96-
/// </summary>
97-
internal SqlRetryLogicBaseProvider ConnectionProvider { get; private set; }
98-
99-
/// <summary>
100-
/// Default Retry provider for SqlCommands
101-
/// </summary>
102-
internal SqlRetryLogicBaseProvider CommandProvider { get; private set; }
103-
}
104-
10591
internal interface IAppContextSwitchOverridesSection
10692
{
10793
string Value { get; set; }

0 commit comments

Comments
 (0)