Repository navigation
Fix | Load and resolve retry logic providers into the current AssemblyLoadContext #4588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
edwardneal
wants to merge
19
commits into
dotnet:main
Choose a base branch
from
edwardneal:feat/retrylogic-current-alc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+537
−169
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
3b01352
Load and resolve assemblies into the current AssemblyLoadContext
edwardneal 37adeda
Create new UnloadableLibrary type/project to test AssemblyLoadContext…
edwardneal 15ea6e9
Merge main
edwardneal bb136df
Load types into current AssemblyLoadContext
edwardneal 524a696
Adjust comments in tests
edwardneal 8a11067
Move RetryLogicConfigHelper class to TestCommon, rename
edwardneal fd0bb76
Remove old copy of RetryLogicConfigHelper from ManualTests
edwardneal a495eab
Use a class derived from AssemblyLoadContext to block the use of the …
edwardneal 79f51b9
Add assertions to verify that the SqlClient assembly is loaded into t…
edwardneal 3708cf5
Address comments
edwardneal 8e715a0
Cleanup tests
edwardneal bd0ba5b
Move LocalAppContextSwitchesHelper to inside ALC
edwardneal ad8edb9
Add and modify comments
edwardneal e2c04e3
Missing constructor documentation
edwardneal 5371672
Merge branch 'main' into feat/retrylogic-current-alc
edwardneal 6536050
Post-merge corrections to new library's compilation
edwardneal a9c7950
Guard Dispose and Unload in a try/finally
edwardneal 26fe548
Ensure RetryLogicType contains assembly-qualified name
edwardneal a8396ed
Fix typo
edwardneal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/Microsoft.Data.SqlClient/tests/Common/ConfigurableRetryLogic/RetryLogicConfigs.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| namespace Microsoft.Data.SqlClient.Tests.Common.ConfigurableRetryLogic; | ||
|
|
||
| /// <summary> | ||
| /// Transport object for retry logic configuration parameters. This is used to pass | ||
| /// values which would ordinarily be part of the SqlConfigurableRetryLogicConnection | ||
| /// or SqlConfigurableRetryLogicCommand section to <see cref="RetryLogicLoaderHelper.CreateLoader"/> | ||
| /// </summary> | ||
| public sealed class RetryLogicConfigs | ||
| { | ||
| /// <summary> | ||
| /// Equivalent of the deltaTime value in an app.config file. | ||
| /// </summary> | ||
| public TimeSpan DeltaTime { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the maxTime value in an app.config file. | ||
| /// </summary> | ||
| public TimeSpan MaxTimeInterval { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the minTime value in an app.config file. | ||
| /// </summary> | ||
| public TimeSpan MinTimeInterval { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the numberOfTries value in an app.config file. | ||
| /// </summary> | ||
| public int NumberOfTries { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the transientErrors value in an app.config file. | ||
| /// </summary> | ||
| public string? TransientErrors { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the authorizedSqlCondition value in an app.config file. | ||
| /// </summary> | ||
| public string? AuthorizedSqlCondition { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the retryLogicType value in an app.config file. | ||
| /// </summary> | ||
| public string? RetryLogicType { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Equivalent of the retryMethod value in an app.config file. | ||
| /// </summary> | ||
| public string? RetryMethodName { get; set; } | ||
| } |
128 changes: 128 additions & 0 deletions
128
src/Microsoft.Data.SqlClient/tests/Common/ConfigurableRetryLogic/RetryLogicLoaderHelper.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| using System.Reflection; | ||
|
|
||
| namespace Microsoft.Data.SqlClient.Tests.Common.ConfigurableRetryLogic; | ||
|
|
||
| /// <summary> | ||
| /// Contains helper methods for creating and configuring instances of | ||
| /// SqlConfigurableRetryLogicLoader and its associated configuration objects without needing | ||
| /// to populate an app.config file. | ||
| /// </summary> | ||
| public static class RetryLogicLoaderHelper | ||
|
|
||
| { | ||
| private const string ConfigurationLoaderTypeName = "Microsoft.Data.SqlClient.SqlConfigurableRetryLogicLoader"; | ||
| private const string InterfaceCnnCfgTypeName = "Microsoft.Data.SqlClient.ISqlConfigurableRetryConnectionSection"; | ||
| private const string InterfaceCmdCfgTypeName = "Microsoft.Data.SqlClient.ISqlConfigurableRetryCommandSection"; | ||
| private const string CnnCfgTypeName = "Microsoft.Data.SqlClient.SqlConfigurableRetryConnectionSection"; | ||
| private const string CmdCfgTypeName = "Microsoft.Data.SqlClient.SqlConfigurableRetryCommandSection"; | ||
| private const string DefaultTransientErrors = "1204, 1205, 1222, 49918, 49919, 49920, 4060, 4221, 40143, 40613, 40501, 40540, 40197, 42108, 42109, 10929, 10928, 10060, 10054, 10053, 997, 233, 64, 20, 0, -2, 207, 102, 2812"; | ||
|
|
||
| private static readonly Random s_random = new(); | ||
|
|
||
| private static readonly Assembly s_sqlClientAssembly = typeof(SqlConnection).Assembly; | ||
| private static readonly Type s_configurationLoaderType = s_sqlClientAssembly.GetType(ConfigurationLoaderTypeName)!; | ||
| private static readonly Type s_interfaceCnnCfgType = s_sqlClientAssembly.GetType(InterfaceCnnCfgTypeName)!; | ||
| private static readonly Type s_interfaceCmdCfgType = s_sqlClientAssembly.GetType(InterfaceCmdCfgTypeName)!; | ||
| private static readonly Type s_cnnCfgType = s_sqlClientAssembly.GetType(CnnCfgTypeName)!; | ||
| private static readonly Type s_cmdCfgType = s_sqlClientAssembly.GetType(CmdCfgTypeName)!; | ||
|
|
||
| private static readonly Type[] s_cfgLoaderParamsType = | ||
| [ | ||
| s_interfaceCnnCfgType, | ||
| s_interfaceCmdCfgType, | ||
| typeof(string), typeof(string) | ||
| ]; | ||
| private static readonly ConstructorInfo s_loaderCtorInfo = s_configurationLoaderType.GetConstructor(s_cfgLoaderParamsType)!; | ||
|
|
||
| /// <summary> | ||
| /// Creates and returns an instance of SqlConfigurableRetryLogicLoader with the specified | ||
| /// connection and command retry logic configurations. | ||
| /// </summary> | ||
| /// <param name="cnnConfig">The configuration for the connection retry logic.</param> | ||
| /// <param name="cmdConfig">The configuration for the command retry logic.</param> | ||
| /// <returns>The created loader instance.</returns> | ||
| public static object CreateLoader(RetryLogicConfigs cnnConfig, RetryLogicConfigs cmdConfig) | ||
| { | ||
| object cnnCfgObj = Activator.CreateInstance(s_cnnCfgType)!; | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "DeltaTime", cnnConfig.DeltaTime); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "MinTimeInterval", cnnConfig.MinTimeInterval); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "MaxTimeInterval", cnnConfig.MaxTimeInterval); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "NumberOfTries", cnnConfig.NumberOfTries); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "AuthorizedSqlCondition", cnnConfig.AuthorizedSqlCondition); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "TransientErrors", cnnConfig.TransientErrors); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "RetryLogicType", cnnConfig.RetryLogicType); | ||
| SetValue(cnnCfgObj, s_cnnCfgType, "RetryMethod", cnnConfig.RetryMethodName); | ||
|
|
||
| object cmdCfgObj = Activator.CreateInstance(s_cmdCfgType)!; | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "DeltaTime", cmdConfig.DeltaTime); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "MinTimeInterval", cmdConfig.MinTimeInterval); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "MaxTimeInterval", cmdConfig.MaxTimeInterval); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "NumberOfTries", cmdConfig.NumberOfTries); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "AuthorizedSqlCondition", cmdConfig.AuthorizedSqlCondition); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "TransientErrors", cmdConfig.TransientErrors); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "RetryLogicType", cmdConfig.RetryLogicType); | ||
| SetValue(cmdCfgObj, s_cmdCfgType, "RetryMethod", cmdConfig.RetryMethodName); | ||
|
|
||
| return s_loaderCtorInfo.Invoke([cnnCfgObj, cmdCfgObj, default!, default!]); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates and returns an instance of SqlConfigurableRetryLogicLoader with the specified | ||
| /// connection and command retry logic configurations, and also retrieves the associated | ||
| /// connection and command providers. | ||
| /// </summary> | ||
| /// <param name="cnnCfg">The configuration for the connection retry logic.</param> | ||
| /// <param name="cmdCfg">The configuration for the command retry logic.</param> | ||
| /// <param name="cnnProvider">When this method returns, contains the connection provider.</param> | ||
| /// <param name="cmdProvider">When this method returns, contains the command provider.</param> | ||
| /// <returns>The created loader instance.</returns> | ||
| public static object ReturnLoaderAndProviders(RetryLogicConfigs cnnCfg, RetryLogicConfigs cmdCfg, out SqlRetryLogicBaseProvider cnnProvider, out SqlRetryLogicBaseProvider cmdProvider) | ||
| { | ||
| object loaderObj = CreateLoader(cnnCfg, cmdCfg); | ||
|
|
||
| cnnProvider = GetValue<SqlRetryLogicBaseProvider>(loaderObj, s_configurationLoaderType, "ConnectionProvider"); | ||
| cmdProvider = GetValue<SqlRetryLogicBaseProvider>(loaderObj, s_configurationLoaderType, "CommandProvider"); | ||
| return loaderObj; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a RetryLogicConfigs object with random values for its properties, optionally specifying | ||
| /// default values for certain mandatory properties. | ||
| /// </summary> | ||
| /// <param name="method">The retry method to use.</param> | ||
| /// <param name="authorizedSqlCondition">The authorized SQL condition.</param> | ||
| /// <param name="transientErrors">The transient errors.</param> | ||
| /// <returns>The created retry logic configuration.</returns> | ||
| public static RetryLogicConfigs CreateRandomConfig(string? method, string? authorizedSqlCondition = null, string transientErrors = DefaultTransientErrors) | ||
| { | ||
| TimeSpan start = TimeSpan.Zero; | ||
| TimeSpan end = TimeSpan.FromSeconds(60); | ||
| TimeSpan min = GenerateTimeSpan(start, end); | ||
|
|
||
| return new RetryLogicConfigs() | ||
| { | ||
| DeltaTime = GenerateTimeSpan(start, end), | ||
| MinTimeInterval = min, | ||
| MaxTimeInterval = GenerateTimeSpan(min, end), | ||
| NumberOfTries = s_random.Next(1, 60), | ||
| AuthorizedSqlCondition = authorizedSqlCondition, | ||
| TransientErrors = transientErrors, | ||
| RetryMethodName = method | ||
| }; | ||
| } | ||
|
|
||
| private static T GetValue<T>(object obj, Type type, string propName, BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) => | ||
| (T)type.GetProperty(propName, flags)?.GetValue(obj)!; | ||
|
|
||
| private static void SetValue<T>(object obj, Type type, string propName, T value, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance) => | ||
| type.GetProperty(propName, flags)?.SetValue(obj, value); | ||
|
|
||
| private static TimeSpan GenerateTimeSpan(TimeSpan start, TimeSpan end) | ||
| { | ||
| int max = (int)(end - start).TotalSeconds; | ||
| return start.Add(TimeSpan.FromSeconds(s_random.Next(max))); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.