diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs
index b48ea36958..0f40a70df7 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs
@@ -37,7 +37,7 @@ internal sealed class SNINpHandle : SNIPhysicalHandle
private int _bufferSize = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE;
private readonly Guid _connectionId = Guid.NewGuid();
- public SNINpHandle(string serverName, string pipeName, long timerExpire, bool tlsFirst)
+ public SNINpHandle(string serverName, string pipeName, long timerExpire, bool tlsFirst, bool isAsyncOption)
{
using (TrySNIEventScope.Create(nameof(SNINpHandle)))
{
@@ -48,11 +48,13 @@ public SNINpHandle(string serverName, string pipeName, long timerExpire, bool tl
_tlsFirst = tlsFirst;
try
{
+ PipeOptions pipeOptions = isAsyncOption ? PipeOptions.Asynchronous | PipeOptions.WriteThrough : PipeOptions.WriteThrough;
+
_pipeStream = new NamedPipeClientStream(
serverName,
pipeName,
PipeDirection.InOut,
- PipeOptions.Asynchronous | PipeOptions.WriteThrough);
+ pipeOptions);
bool isInfiniteTimeOut = long.MaxValue == timerExpire;
if (isInfiniteTimeOut)
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs
index ac4d3599dd..7a1d1083e1 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs
@@ -192,7 +192,7 @@ internal static SNIHandle CreateConnectionHandle(
tlsFirst, hostNameInCertificate, serverCertificateFilename);
break;
case DataSource.Protocol.NP:
- sniHandle = CreateNpHandle(details, timerExpire, parallel, tlsFirst);
+ sniHandle = CreateNpHandle(details, timerExpire, parallel, tlsFirst, isAsyncOption : async);
break;
default:
Debug.Fail($"Unexpected connection protocol: {details._connectionProtocol}");
@@ -348,8 +348,9 @@ private static SNITCPHandle CreateTcpHandle(
/// Timer expiration
/// Should MultiSubnetFailover be used. Only returns an error for named pipes.
///
+ ///
/// SNINpHandle
- private static SNINpHandle CreateNpHandle(DataSource details, long timerExpire, bool parallel, bool tlsFirst)
+ private static SNINpHandle CreateNpHandle(DataSource details, long timerExpire, bool parallel, bool tlsFirst, bool isAsyncOption)
{
if (parallel)
{
@@ -357,7 +358,7 @@ private static SNINpHandle CreateNpHandle(DataSource details, long timerExpire,
SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, Strings.SNI_ERROR_49);
return null;
}
- return new SNINpHandle(details.PipeHostName, details.PipeName, timerExpire, tlsFirst);
+ return new SNINpHandle(details.PipeHostName, details.PipeName, timerExpire, tlsFirst, isAsyncOption);
}
///
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
index 660b5934e0..5f6427aa25 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -38,6 +38,7 @@ private enum CultureCheckState : uint
}
private bool _AsyncCommandInProgress;
+ private bool _isAsyncPipeOption = false;
// SQLStatistics support
internal SqlStatistics _statistics;
@@ -496,6 +497,11 @@ internal bool AsyncCommandInProgress
set => _AsyncCommandInProgress = value;
}
+ internal bool IsAsyncPipeOption
+ {
+ get => _isAsyncPipeOption;
+ }
+
private bool UsesActiveDirectoryIntegrated(SqlConnectionString opt)
{
return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated;
@@ -1589,6 +1595,8 @@ private Task InternalOpenAsync(CancellationToken cancellationToken)
{
long scopeID = SqlClientEventSource.Log.TryPoolerScopeEnterEvent("SqlConnection.InternalOpenAsync | API | Object Id {0}", ObjectID);
SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.InternalOpenAsync | API | Correlation | Object Id {0}, Activity Id {1}", ObjectID, ActivityCorrelator.Current);
+ _isAsyncPipeOption = true;
+
try
{
Guid operationId = s_diagnosticListener.WriteConnectionOpenBefore(this);
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index e977641175..4e0035f020 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -1911,7 +1911,8 @@ private void AttemptOneLogin(
ignoreSniOpenTimeout,
timeout.LegacyTimerExpire,
ConnectionOptions,
- withFailover);
+ withFailover,
+ Connection.IsAsyncPipeOption);
_timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake);
_timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin);
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs
index 8217604c72..913377adea 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs
@@ -364,7 +364,8 @@ internal void Connect(
bool ignoreSniOpenTimeout,
long timerExpire,
SqlConnectionString connectionOptions,
- bool withFailover)
+ bool withFailover,
+ bool isAsyncPipeOption)
{
SqlConnectionEncryptOption encrypt = connectionOptions.Encrypt;
bool isTlsFirst = (encrypt == SqlConnectionEncryptOption.Strict);
@@ -443,6 +444,7 @@ internal void Connect(
_connHandler.pendingSQLDNSObject = null;
// AD Integrated behaves like Windows integrated when connecting to a non-fedAuth server
+
_physicalStateObj.CreatePhysicalSNIHandle(
serverInfo.ExtendedServerName,
ignoreSniOpenTimeout,
@@ -450,7 +452,7 @@ internal void Connect(
out instanceName,
ref _sniSpnBuffer,
false,
- true,
+ async: isAsyncPipeOption,
fParallel,
_connHandler.ConnectionOptions.IPAddressPreference,
FQDNforDNSCache,
@@ -545,10 +547,11 @@ internal void Connect(
_physicalStateObj.CreatePhysicalSNIHandle(
serverInfo.ExtendedServerName,
ignoreSniOpenTimeout,
- timerExpire, out instanceName,
+ timerExpire,
+ out instanceName,
ref _sniSpnBuffer,
true,
- true,
+ async: isAsyncPipeOption,
fParallel,
_connHandler.ConnectionOptions.IPAddressPreference,
FQDNforDNSCache,
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlConnectionReliabilityTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlConnectionReliabilityTest.cs
index 624912f260..1aea785935 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlConnectionReliabilityTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlConnectionReliabilityTest.cs
@@ -130,6 +130,41 @@ public void ConcurrentExecution(string cnnString, SqlRetryLogicBaseProvider prov
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
}
+#if NETCOREAPP
+
+ [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
+ [MemberData(nameof(RetryLogicTestHelper.GetConnectionAndRetryStrategyInvalidCatalog), parameters: new object[] { 2 }, MemberType = typeof(RetryLogicTestHelper), DisableDiscoveryEnumeration = true)]
+ public async Task ConcurrentExecutionAsync(string cnnString, SqlRetryLogicBaseProvider provider)
+ {
+ int numberOfTries = provider.RetryLogic.NumberOfTries;
+ int cancelAfterRetries = numberOfTries + 1;
+ int retriesCount = 0;
+ int concurrentExecution = 5;
+ provider.Retrying += (s, e) => Interlocked.Increment(ref retriesCount);
+
+ await Parallel.ForEachAsync(System.Linq.Enumerable.Range(0, concurrentExecution),
+ async (i, c) =>
+ {
+ using (var cnn = CreateConnectionWithInvalidCatalog(cnnString, provider, cancelAfterRetries))
+ {
+ await Assert.ThrowsAsync(async () => await cnn.OpenAsync());
+ }
+ });
+ Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
+
+ retriesCount = 0;
+ Parallel.For(0, concurrentExecution,
+ i =>
+ {
+ using (var cnn = CreateConnectionWithInvalidCatalog(cnnString, provider, cancelAfterRetries))
+ {
+ Assert.ThrowsAsync(() => cnn.OpenAsync()).Wait();
+ }
+ });
+ Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
+ }
+#endif
+
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
[MemberData(nameof(RetryLogicTestHelper.GetNoneRetriableCondition), MemberType = typeof(RetryLogicTestHelper), DisableDiscoveryEnumeration = true)]
public void DefaultOpenWithoutRetry(string connectionString, SqlRetryLogicBaseProvider cnnProvider)