From 06d178ae7a3123c41c62fe6ffc59c7b93437deac Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 09:08:29 -0700 Subject: [PATCH 1/6] Remove cascading user options parameter only used for debug assertions. Co-authored-by: Copilot --- .../Data/ProviderBase/DbConnectionClosed.cs | 21 ++++------- .../Data/ProviderBase/DbConnectionInternal.cs | 13 +++---- .../Connection/SqlConnectionInternal.cs | 31 +--------------- .../ConnectionPool/ChannelDbConnectionPool.cs | 12 +----- .../ConnectionPool/IDbConnectionPool.cs | 8 ++-- .../Microsoft/Data/SqlClient/SqlConnection.cs | 4 +- .../Data/SqlClient/SqlConnectionFactory.cs | 37 +++++-------------- 7 files changed, 30 insertions(+), 96 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionClosed.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionClosed.cs index 2bb0c202a7..96704bacce 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionClosed.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionClosed.cs @@ -62,9 +62,8 @@ protected internal override Task GetSchemaAsync( internal override bool TryOpenConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) => - TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions); + TaskCompletionSource retry) => + TryOpenConnectionInternal(outerConnection, connectionFactory, retry); /// internal override void ResetConnection() => throw ADP.ClosedConnectionError(); @@ -79,8 +78,7 @@ protected DbConnectionBusy(ConnectionState state) : base(state, true, false) internal override bool TryOpenConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) => throw ADP.ConnectionAlreadyOpen(State); } @@ -121,15 +119,13 @@ internal override void CloseConnection(DbConnection owningObject, SqlConnectionF internal override bool TryReplaceConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) => - TryOpenConnection(outerConnection, connectionFactory, retry, userOptions); + TaskCompletionSource retry) => + TryOpenConnection(outerConnection, connectionFactory, retry); internal override bool TryOpenConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) { if (retry == null || !retry.Task.IsCompleted) { @@ -177,8 +173,7 @@ private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true internal override bool TryReplaceConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) => - TryOpenConnection(outerConnection, connectionFactory, retry, userOptions); + TaskCompletionSource retry) => + TryOpenConnection(outerConnection, connectionFactory, retry); } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index b6b6d727ed..ac3949c726 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -688,7 +688,7 @@ internal void MakePooledConnection(IDbConnectionPool connectionPool) internal virtual void OpenConnection(DbConnection outerConnection, SqlConnectionFactory connectionFactory) { - if (!TryOpenConnection(outerConnection, connectionFactory, null, null)) + if (!TryOpenConnection(outerConnection, connectionFactory, null)) { throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending); } @@ -800,8 +800,7 @@ internal void SetInStasis() internal virtual bool TryOpenConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) { throw ADP.ConnectionAlreadyOpen(State); } @@ -809,8 +808,7 @@ internal virtual bool TryOpenConnection( internal virtual bool TryReplaceConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) { throw ADP.MethodNotImplemented(); } @@ -912,8 +910,7 @@ protected virtual void ReleaseAdditionalLocksForClose(bool lockToken) protected bool TryOpenConnectionInternal( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) { // ?->Connecting: prevent set_ConnectionString during Open if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this)) @@ -922,7 +919,7 @@ protected bool TryOpenConnectionInternal( try { connectionFactory.PermissionDemand(outerConnection); - if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection)) + if (!connectionFactory.TryGetConnection(outerConnection, retry, this, out openConnection)) { return false; } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Connection/SqlConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Connection/SqlConnectionInternal.cs index 6c5be8930c..e62541137c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Connection/SqlConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Connection/SqlConnectionInternal.cs @@ -312,8 +312,6 @@ internal class SqlConnectionInternal : DbConnectionInternal, IDisposable /// - Although the new password is generally not used it must be passed to the ctor. The /// new Login7 packet will always write out the new password (or a length of zero and no /// bytes if not present). - /// - userConnectionOptions may be different to connectionOptions if the connection string - /// has been expanded (see SqlConnectionOptions.Expand) /// // @TODO: We really really need simplify what we pass into this. All these optional parameters need to go! internal SqlConnectionInternal( @@ -324,7 +322,6 @@ internal SqlConnectionInternal( string newPassword, SecureString newSecurePassword, bool redirectedUserInstance, - SqlConnectionOptions userConnectionOptions = null, SessionData reconnectSessionData = null, bool applyTransientFaultHandling = false, string accessToken = null, @@ -341,29 +338,6 @@ internal SqlConnectionInternal( { reconnectSessionData._debugReconnectDataApplied = true; } - - #if NETFRAMEWORK - try - { - // use this to help validate this object is only created after the following - // permission has been previously demanded in the current codepath - if (userConnectionOptions != null) - { - // As mentioned above, userConnectionOptions may be different to - // connectionOptions, so we need to demand on the correct connection string - userConnectionOptions.DemandPermission(); - } - else - { - connectionOptions.DemandPermission(); - } - } - catch (SecurityException) - { - Debug.Assert(false, "unexpected SecurityException for current codepath"); - throw; - } - #endif #endif Debug.Assert(reconnectSessionData == null || connectionOptions.ConnectRetryCount > 0, @@ -1970,10 +1944,9 @@ internal void OnLoginAck(SqlLoginAck rec) internal override bool TryReplaceConnection( DbConnection outerConnection, SqlConnectionFactory connectionFactory, - TaskCompletionSource retry, - SqlConnectionOptions userOptions) + TaskCompletionSource retry) { - return TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions); + return TryOpenConnectionInternal(outerConnection, connectionFactory, retry); } internal void ValidateConnectionForExecute(SqlCommand command) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs index 41d49508be..b83434cac6 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs @@ -224,7 +224,6 @@ public void PutObjectFromTransactedPool(DbConnectionInternal connection) /// public DbConnectionInternal ReplaceConnection( DbConnection owningObject, - SqlConnectionOptions userOptions, DbConnectionInternal oldConnection) { throw new NotImplementedException(); @@ -282,7 +281,6 @@ public void TransactionEnded(Transaction transaction, DbConnectionInternal trans public bool TryGetConnection( DbConnection owningObject, TaskCompletionSource? taskCompletionSource, - SqlConnectionOptions userOptions, out DbConnectionInternal? connection) { var timeout = TimeSpan.FromSeconds(owningObject.ConnectionTimeout); @@ -292,7 +290,6 @@ public bool TryGetConnection( { var task = GetInternalConnection( owningObject, - userOptions, async: false, timeout); @@ -340,7 +337,6 @@ public bool TryGetConnection( { connection = await GetInternalConnection( owningObject, - userOptions, async: true, timeout ).ConfigureAwait(false); @@ -375,7 +371,6 @@ public bool TryGetConnection( /// Opens a new internal connection to the database. /// /// The owning connection. - /// The options for the connection. /// The cancellation token to cancel the operation. /// A task representing the asynchronous operation, with a result of the new internal connection. /// @@ -383,7 +378,6 @@ public bool TryGetConnection( /// private DbConnectionInternal? OpenNewInternalConnection( DbConnection? owningConnection, - SqlConnectionOptions userOptions, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -405,8 +399,7 @@ public bool TryGetConnection( // when this support is added to DbConnectionInternal. var connection = ConnectionFactory.CreatePooledConnection( owningConnection, - this, - userOptions); + this); if (connection is not null) { @@ -498,7 +491,6 @@ private void RemoveConnection(DbConnectionInternal connection) /// Gets an internal connection from the pool, either by retrieving an idle connection or opening a new one. /// /// The DbConnection that will own this internal connection - /// The user options to set on the internal connection /// A boolean indicating whether the operation should be asynchronous. /// The timeout for the operation. /// Returns a DbConnectionInternal that is retrieved from the pool. @@ -512,7 +504,6 @@ private void RemoveConnection(DbConnectionInternal connection) /// private async Task GetInternalConnection( DbConnection owningConnection, - SqlConnectionOptions userOptions, bool async, TimeSpan timeout) { @@ -533,7 +524,6 @@ private async Task GetInternalConnection( // If we didn't find an idle connection, try to open a new one. connection ??= OpenNewInternalConnection( owningConnection, - userOptions, cancellationToken); // If we're at max capacity and couldn't open a connection. Block on the idle channel with a diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/IDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/IDbConnectionPool.cs index 904c19f28e..43dae3fa0f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/IDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/IDbConnectionPool.cs @@ -119,19 +119,17 @@ internal interface IDbConnectionPool /// The SqlConnection that will own this internal connection. /// Used when calling this method in an async context. /// The internal connection will be set on completion source rather than passed out via the out parameter. - /// The user options to use if a new connection must be opened. /// The retrieved connection will be passed out via this parameter. /// True if a connection was set in the out parameter, otherwise returns false. - bool TryGetConnection(DbConnection owningObject, TaskCompletionSource? taskCompletionSource, SqlConnectionOptions userOptions, out DbConnectionInternal? connection); + bool TryGetConnection(DbConnection owningObject, TaskCompletionSource? taskCompletionSource, out DbConnectionInternal? connection); /// /// Replaces the internal connection currently associated with owningObject with a new internal connection from the pool. /// - /// The connection whos internal connection should be replaced. - /// The user options to use if a new connection must be opened. + /// The connection whose internal connection should be replaced. /// The internal connection currently associated with the owning object. /// A reference to the new DbConnectionInternal. - DbConnectionInternal ReplaceConnection(DbConnection owningObject, SqlConnectionOptions userOptions, DbConnectionInternal oldConnection); + DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbConnectionInternal oldConnection); /// /// Returns an internal connection to the pool. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs index b0c9cc4289..aa9d8edc06 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -2228,14 +2228,14 @@ private bool TryOpenInner(TaskCompletionSource retry) { if (ForceNewConnection) { - if (!InnerConnection.TryReplaceConnection(this, ConnectionFactory, retry, UserConnectionOptions)) + if (!InnerConnection.TryReplaceConnection(this, ConnectionFactory, retry)) { return false; } } else { - if (!InnerConnection.TryOpenConnection(this, ConnectionFactory, retry, UserConnectionOptions)) + if (!InnerConnection.TryOpenConnection(this, ConnectionFactory, retry)) { return false; } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs index 981ca17641..30010d0d4b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs @@ -115,8 +115,7 @@ internal DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(SqlConnec internal DbConnectionInternal CreateNonPooledConnection( DbConnection owningConnection, - DbConnectionPoolGroup poolGroup, - SqlConnectionOptions userOptions) + DbConnectionPoolGroup poolGroup) { Debug.Assert(owningConnection is not null, "null owningConnection?"); Debug.Assert(poolGroup is not null, "null poolGroup?"); @@ -126,8 +125,7 @@ internal DbConnectionInternal CreateNonPooledConnection( poolGroup.PoolKey, poolGroup.ProviderInfo, pool: null, - owningConnection, - userOptions); + owningConnection); if (newConnection is not null) { SqlClientDiagnostics.Metrics.HardConnectRequest(); @@ -140,8 +138,7 @@ internal DbConnectionInternal CreateNonPooledConnection( internal DbConnectionInternal CreatePooledConnection( DbConnection owningConnection, - IDbConnectionPool pool, - SqlConnectionOptions userOptions) + IDbConnectionPool pool) { Debug.Assert(pool != null, "null pool?"); @@ -150,8 +147,7 @@ internal DbConnectionInternal CreatePooledConnection( pool.PoolGroup.PoolKey, pool.PoolGroup.ProviderInfo, pool, - owningConnection, - userOptions); + owningConnection); if (newConnection is null) { @@ -316,7 +312,6 @@ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) internal bool TryGetConnection( DbConnection owningConnection, TaskCompletionSource retry, - SqlConnectionOptions userOptions, DbConnectionInternal oldConnection, out DbConnectionInternal connection) { @@ -387,7 +382,6 @@ internal bool TryGetConnection( s_pendingOpenNonPooled[idx], owningConnection, retry, - userOptions, oldConnection, poolGroup, cancellationTokenSource); @@ -413,7 +407,7 @@ internal bool TryGetConnection( return false; } - connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); + connection = CreateNonPooledConnection(owningConnection, poolGroup); SqlClientDiagnostics.Metrics.EnterNonPooledConnection(); } @@ -423,11 +417,11 @@ internal bool TryGetConnection( { Debug.Assert(oldConnection is not DbConnectionClosed, "Force new connection, but there is no old connection"); - connection = connectionPool.ReplaceConnection(owningConnection, userOptions, oldConnection); + connection = connectionPool.ReplaceConnection(owningConnection, oldConnection); } else { - if (!connectionPool.TryGetConnection(owningConnection, retry, userOptions, out connection)) + if (!connectionPool.TryGetConnection(owningConnection, retry, out connection)) { return false; } @@ -579,8 +573,7 @@ protected virtual DbConnectionInternal CreateConnection( ConnectionPoolKey poolKey, DbConnectionPoolGroupProviderInfo poolGroupProviderInfo, IDbConnectionPool pool, - DbConnection owningConnection, - SqlConnectionOptions userOptions) + DbConnection owningConnection) { SqlConnectionOptions opt = options; ConnectionPoolKey key = poolKey; @@ -589,16 +582,6 @@ protected virtual DbConnectionInternal CreateConnection( SqlConnection sqlOwningConnection = owningConnection as SqlConnection; bool applyTransientFaultHandling = sqlOwningConnection?._applyTransientFaultHandling ?? false; - SqlConnectionOptions userOpt = null; - if (userOptions != null) - { - userOpt = userOptions; - } - else if (sqlOwningConnection != null) - { - userOpt = sqlOwningConnection.UserConnectionOptions; - } - if (sqlOwningConnection != null) { recoverySessionData = sqlOwningConnection._recoverySessionData; @@ -700,7 +683,6 @@ protected virtual DbConnectionInternal CreateConnection( newPassword: string.Empty, newSecurePassword: null, redirectedUserInstance, - userOpt, recoverySessionData, applyTransientFaultHandling, key.AccessToken, @@ -768,7 +750,6 @@ private Task CreateReplaceConnectionContinuation( Task task, DbConnection owningConnection, TaskCompletionSource retry, - SqlConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionPoolGroup poolGroup, CancellationTokenSource cancellationTokenSource) @@ -781,7 +762,7 @@ private Task CreateReplaceConnectionContinuation( { ADP.SetCurrentTransaction(retry.Task.AsyncState as System.Transactions.Transaction); - DbConnectionInternal newConnection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); + DbConnectionInternal newConnection = CreateNonPooledConnection(owningConnection, poolGroup); if (oldConnection?.State == ConnectionState.Open) { From d6fb50a682105e52599413bbc962bd4f6ad6afa3 Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 09:49:44 -0700 Subject: [PATCH 2/6] Fix pool and pooling tests. --- .../WaitHandleDbConnectionPool.cs | 34 ++++++-------- .../ChannelDbConnectionPoolTest.cs | 46 ++----------------- .../TransactedConnectionPoolTest.cs | 4 +- ...itHandleDbConnectionPoolTransactionTest.cs | 5 +- 4 files changed, 21 insertions(+), 68 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs index 96a1a6e5f3..25b40d30c0 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs @@ -61,17 +61,15 @@ internal sealed class WaitHandleDbConnectionPool : IDbConnectionPool private sealed class PendingGetConnection { - public PendingGetConnection(long dueTime, DbConnection owner, TaskCompletionSource completion, SqlConnectionOptions userOptions) + public PendingGetConnection(long dueTime, DbConnection owner, TaskCompletionSource completion) { DueTime = dueTime; Owner = owner; Completion = completion; - UserOptions = userOptions; } public long DueTime { get; private set; } public DbConnection Owner { get; private set; } public TaskCompletionSource Completion { get; private set; } - public SqlConnectionOptions UserOptions { get; private set; } } private sealed class PoolWaitHandles @@ -522,7 +520,7 @@ private bool IsBlockingPeriodEnabled() } } - private DbConnectionInternal CreateObject(DbConnection owningObject, SqlConnectionOptions userOptions, DbConnectionInternal oldConnection) + private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionInternal oldConnection) { DbConnectionInternal newObj = null; @@ -530,8 +528,7 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, SqlConnecti { newObj = _connectionFactory.CreatePooledConnection( owningObject, - this, - userOptions); + this); lock (_objectList) { @@ -837,7 +834,6 @@ private void WaitForPendingOpen() delay, allowCreate: true, onlyOneCheckConnection: false, - next.UserOptions, out connection); } // @TODO: CER Exception Handling was removed here (see GH#3581) @@ -875,7 +871,7 @@ private void WaitForPendingOpen() } while (_pendingOpens.TryPeek(out next)); } - public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource taskCompletionSource, SqlConnectionOptions userOptions, out DbConnectionInternal connection) + public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource taskCompletionSource, out DbConnectionInternal connection) { uint waitForMultipleObjectsTimeout = 0; bool allowCreate = false; @@ -901,7 +897,7 @@ public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource {0}, Creating new connection.", Id); try { - obj = UserCreateRequest(owningObject, userOptions); + obj = UserCreateRequest(owningObject); } catch { @@ -1045,7 +1040,7 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj if (semaphoreHolder.Obtained) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Creating new connection.", Id); - obj = UserCreateRequest(owningObject, userOptions); + obj = UserCreateRequest(owningObject); } else { @@ -1131,13 +1126,12 @@ private void PrepareConnection(DbConnection owningObject, DbConnectionInternal o /// Creates a new connection to replace an existing connection /// /// Outer connection that currently owns - /// Options used to create the new connection /// Inner connection that will be replaced /// A new inner connection that is attached to the - public DbConnectionInternal ReplaceConnection(DbConnection owningObject, SqlConnectionOptions userOptions, DbConnectionInternal oldConnection) + public DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbConnectionInternal oldConnection) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, replacing connection.", Id); - DbConnectionInternal newConnection = UserCreateRequest(owningObject, userOptions, oldConnection); + DbConnectionInternal newConnection = UserCreateRequest(owningObject, oldConnection); if (newConnection != null) { @@ -1278,7 +1272,7 @@ private void PoolCreateRequest(object state) try { // Don't specify any user options because there is no outer connection associated with the new connection - newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null); + newObj = CreateObject(owningObject: null, oldConnection: null); } catch { @@ -1522,7 +1516,7 @@ public void TransactionEnded(Transaction transaction, DbConnectionInternal trans } } - private DbConnectionInternal UserCreateRequest(DbConnection owningObject, SqlConnectionOptions userOptions, DbConnectionInternal oldConnection = null) + private DbConnectionInternal UserCreateRequest(DbConnection owningObject, DbConnectionInternal oldConnection = null) { // called by user when they were not able to obtain a free object but // instead obtained creation mutex @@ -1542,7 +1536,7 @@ private DbConnectionInternal UserCreateRequest(DbConnection owningObject, SqlCon // TODO: Consider implement a control knob here; why do we only check for dead objects ever other time? why not every 10th time or every time? if ((oldConnection != null) || (Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects()) { - obj = CreateObject(owningObject, userOptions, oldConnection); + obj = CreateObject(owningObject, oldConnection); } } return obj; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs index 2b1d437f98..7c1593af14 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -63,7 +63,6 @@ public void GetConnectionEmptyPool_ShouldCreateNewConnection(int numConnections) var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -93,7 +92,6 @@ public async Task GetConnectionAsyncEmptyPool_ShouldCreateNewConnection(int numC var completed = pool.TryGetConnection( new SqlConnection(), tcs, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -119,7 +117,6 @@ public void GetConnectionMaxPoolSize_ShouldTimeoutAfterPeriod() var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -133,7 +130,6 @@ out DbConnectionInternal? internalConnection var exceeded = pool.TryGetConnection( new SqlConnection("Timeout=1"), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? extraConnection ); } @@ -159,7 +155,6 @@ public async Task GetConnectionAsyncMaxPoolSize_ShouldTimeoutAfterPeriod() var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -174,7 +169,6 @@ out DbConnectionInternal? internalConnection var exceeded = pool.TryGetConnection( new SqlConnection("Timeout=1"), taskCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? extraConnection ); await taskCompletionSource.Task; @@ -200,7 +194,6 @@ public async Task GetConnectionMaxPoolSize_ShouldReuseAfterConnectionReleased() pool.TryGetConnection( firstOwningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? firstConnection ); @@ -209,7 +202,6 @@ out DbConnectionInternal? firstConnection var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -225,7 +217,6 @@ out DbConnectionInternal? internalConnection var exceeded = pool.TryGetConnection( new SqlConnection(""), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? extraConnection ); return extraConnection; @@ -247,7 +238,6 @@ public async Task GetConnectionAsyncMaxPoolSize_ShouldReuseAfterConnectionReleas pool.TryGetConnection( firstOwningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? firstConnection ); @@ -256,7 +246,6 @@ out DbConnectionInternal? firstConnection var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -270,7 +259,6 @@ out DbConnectionInternal? internalConnection var exceeded = pool.TryGetConnection( new SqlConnection(""), taskCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? recycledConnection ); pool.ReturnInternalConnection(firstConnection!, firstOwningConnection); @@ -291,7 +279,6 @@ public async Task GetConnectionMaxPoolSize_ShouldRespectOrderOfRequest() pool.TryGetConnection( firstOwningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? firstConnection ); @@ -300,7 +287,6 @@ out DbConnectionInternal? firstConnection var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -321,7 +307,6 @@ out DbConnectionInternal? internalConnection pool.TryGetConnection( new SqlConnection(""), null, - new SqlConnectionOptions(""), out DbConnectionInternal? recycledConnection ); return recycledConnection; @@ -334,7 +319,6 @@ out DbConnectionInternal? recycledConnection pool.TryGetConnection( new SqlConnection("Timeout=1"), null, - new SqlConnectionOptions(""), out DbConnectionInternal? failedConnection ); return failedConnection; @@ -360,7 +344,6 @@ public async Task GetConnectionAsyncMaxPoolSize_ShouldRespectOrderOfRequest() pool.TryGetConnection( firstOwningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? firstConnection ); @@ -369,7 +352,6 @@ out DbConnectionInternal? firstConnection var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -384,7 +366,6 @@ out DbConnectionInternal? internalConnection var exceeded = pool.TryGetConnection( new SqlConnection(""), recycledTaskCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? recycledConnection ); @@ -394,7 +375,6 @@ out DbConnectionInternal? recycledConnection var exceeded2 = pool.TryGetConnection( new SqlConnection("Timeout=1"), failedCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? failedConnection ); @@ -417,7 +397,6 @@ public void ConnectionsAreReused() var completed1 = pool.TryGetConnection( owningConnection, null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection1 ); @@ -432,7 +411,6 @@ out DbConnectionInternal? internalConnection1 var completed2 = pool.TryGetConnection( owningConnection, null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection2 ); @@ -454,7 +432,6 @@ public void GetConnectionTimeout_ShouldThrowTimeoutException() var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); }); @@ -475,7 +452,6 @@ public async Task GetConnectionAsyncTimeout_ShouldThrowTimeoutException() var completed = pool.TryGetConnection( new SqlConnection(), taskCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); @@ -500,7 +476,6 @@ public void StressTest() var completed = pool.TryGetConnection( owningObject, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); if (completed) @@ -534,7 +509,6 @@ public void StressTestAsync() var completed = pool.TryGetConnection( owningObject, taskCompletionSource, - new SqlConnectionOptions(""), out DbConnectionInternal? internalConnection ); internalConnection = await taskCompletionSource.Task; @@ -692,7 +666,7 @@ public void TestPutObjectFromTransactedPool() public void TestReplaceConnection() { var pool = ConstructPool(SuccessfulConnectionFactory); - Assert.Throws(() => pool.ReplaceConnection(null!, null!, null!)); + Assert.Throws(() => pool.ReplaceConnection(null!, null!)); } [Fact] @@ -731,7 +705,6 @@ public void Clear_MultipleIdleConnections_AllAreDestroyed() pool.TryGetConnection( owningConnections[i], taskCompletionSource: null, - new SqlConnectionOptions(""), out internalConnections[i] ); Assert.Equal(0, internalConnections[i]!.ClearGeneration); @@ -760,7 +733,6 @@ public void Clear_BusyConnection_NotDestroyedImmediately() pool.TryGetConnection( owningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? busyConnection ); Assert.NotNull(busyConnection); @@ -784,7 +756,6 @@ public void Clear_BusyConnectionReturned_IsDestroyed() pool.TryGetConnection( owningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? busyConnection ); Assert.NotNull(busyConnection); @@ -814,13 +785,11 @@ public void Clear_MixedBusyAndIdle_OnlyIdleDestroyedImmediately() pool.TryGetConnection( busyOwner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? busyConnection ); pool.TryGetConnection( idleOwner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? idleConnection ); Assert.NotNull(busyConnection); @@ -853,7 +822,6 @@ public void Clear_NewConnectionsAfterClear_ArePooledNormally() pool.TryGetConnection( owningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? oldConnection ); Assert.Equal(0, oldConnection!.ClearGeneration); @@ -867,7 +835,6 @@ out DbConnectionInternal? oldConnection pool.TryGetConnection( newOwner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? newConnection ); Assert.NotNull(newConnection); @@ -885,7 +852,6 @@ out DbConnectionInternal? newConnection pool.TryGetConnection( reuseOwner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? reusedConnection ); Assert.Same(newConnection, reusedConnection); @@ -902,7 +868,6 @@ public void Clear_MultipleClearCalls_DoNotCorruptState() pool.TryGetConnection( owningConnection, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? connection ); Assert.Equal(0, connection!.ClearGeneration); @@ -921,7 +886,6 @@ out DbConnectionInternal? connection pool.TryGetConnection( newOwner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? newConnection ); Assert.NotNull(newConnection); @@ -939,8 +903,7 @@ protected override DbConnectionInternal CreateConnection( ConnectionPoolKey poolKey, DbConnectionPoolGroupProviderInfo poolGroupProviderInfo, IDbConnectionPool pool, - DbConnection owningConnection, - SqlConnectionOptions userOptions) + DbConnection owningConnection) { return new StubDbConnectionInternal(); } @@ -953,8 +916,7 @@ protected override DbConnectionInternal CreateConnection( ConnectionPoolKey poolKey, DbConnectionPoolGroupProviderInfo poolGroupProviderInfo, IDbConnectionPool pool, - DbConnection owningConnection, - SqlConnectionOptions userOptions) + DbConnection owningConnection) { throw ADP.PooledOpenTimeout(); } diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/TransactedConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/TransactedConnectionPoolTest.cs index c03c7cc550..521ded14b8 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/TransactedConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/TransactedConnectionPoolTest.cs @@ -676,12 +676,12 @@ internal class MockDbConnectionPool : IDbConnectionPool public void Clear() => throw new NotImplementedException(); - public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource? taskCompletionSource, SqlConnectionOptions userOptions, out DbConnectionInternal? connection) + public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource? taskCompletionSource, out DbConnectionInternal? connection) { throw new NotImplementedException(); } - public DbConnectionInternal ReplaceConnection(DbConnection owningObject, SqlConnectionOptions userOptions, DbConnectionInternal oldConnection) + public DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbConnectionInternal oldConnection) { throw new NotImplementedException(); } diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/WaitHandleDbConnectionPoolTransactionTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/WaitHandleDbConnectionPoolTransactionTest.cs index 4b4a30ce19..a5e5d0339f 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/WaitHandleDbConnectionPoolTransactionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/WaitHandleDbConnectionPoolTransactionTest.cs @@ -82,7 +82,6 @@ private DbConnectionInternal GetConnection(SqlConnection owner) _pool.TryGetConnection( owner, taskCompletionSource: null, - new SqlConnectionOptions(""), out DbConnectionInternal? connection); return connection!; } @@ -95,7 +94,6 @@ private async Task GetConnectionAsync( _pool.TryGetConnection( owner, taskCompletionSource: tcs, - new SqlConnectionOptions(""), out DbConnectionInternal? connection); return connection ?? await tcs.Task; } @@ -904,8 +902,7 @@ protected override DbConnectionInternal CreateConnection( ConnectionPoolKey poolKey, DbConnectionPoolGroupProviderInfo poolGroupProviderInfo, IDbConnectionPool pool, - DbConnection owningConnection, - SqlConnectionOptions userOptions) + DbConnection owningConnection) { return new MockDbConnectionInternal(); } From d83f79d67a33478275d27e93660b2c0b3443b712 Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 13:29:01 -0700 Subject: [PATCH 3/6] Add tests for permission demands. --- .../Microsoft/Data/SqlClient/CasTest.cs | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs new file mode 100644 index 0000000000..fbb486a3ae --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs @@ -0,0 +1,135 @@ +// 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. + +#if NETFRAMEWORK +using System; +using System.Data; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.Microsoft.Data.SqlClient +{ + /// + /// Tests for Code Access Security (CAS) permission demands in SqlConnection. + /// + /// CAS is a .NET Framework security mechanism that restricts what code can do based on + /// its origin and identity. SqlConnection.Open() calls DemandPermission(), which performs + /// a stack walk to verify that all callers have been granted SqlClientPermission. If any + /// caller lacks the permission, a SecurityException is thrown before any network I/O occurs. + /// + /// These tests use AppDomain sandboxing to create partial-trust environments with controlled + /// permission sets, proving that the permission demand is enforced during Open(). + /// + public class CasTest + { + /// + /// Verify that calling Open() in a partial-trust sandbox without SqlClientPermission + /// causes a SecurityException. Paired with the next test, this experimentally proves + /// that SqlClientPermission is the specific permission being demanded: the only + /// difference between the two sandboxes is SqlClientPermission being granted. + /// + [Fact] + public void Open_WithoutSqlClientPermission_ThrowsSecurityException() + { + var permissions = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None); + permissions.AddPermission(new System.Security.Permissions.SecurityPermission( + System.Security.Permissions.SecurityPermissionFlag.Execution)); + + var setup = new AppDomainSetup + { + ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + }; + + AppDomain sandbox = AppDomain.CreateDomain("PermissionTest_NoPerm", null, setup, permissions); + try + { + Assert.Throws(() => + sandbox.DoCallBack(OpenConnectionInSandbox)); + } + finally + { + AppDomain.Unload(sandbox); + } + } + + /// + /// Same sandbox as above, but with a narrow SqlClientPermission granted for the exact + /// connection string used in OpenConnectionInSandbox. The SecurityException goes away, + /// proving that the CAS demand is specifically for SqlClientPermission scoped to that + /// connection string. (Open still fails with a non-security error because we can't connect.) + /// + [Fact] + public void Open_WithSqlClientPermission_DoesNotThrowSecurityException() + { + var permissions = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None); + permissions.AddPermission(new System.Security.Permissions.SecurityPermission( + System.Security.Permissions.SecurityPermissionFlag.Execution)); + var sqlPerm = new SqlClientPermission(System.Security.Permissions.PermissionState.None); + sqlPerm.Add("Server=will_not_resolve_12345;", "", KeyRestrictionBehavior.AllowOnly); + permissions.AddPermission(sqlPerm); + + var setup = new AppDomainSetup + { + ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + }; + + AppDomain sandbox = AppDomain.CreateDomain("PermissionTest_WithPerm", null, setup, permissions); + try + { + var ex = Record.Exception(() => sandbox.DoCallBack(OpenConnectionInSandbox)); + Assert.NotNull(ex); + Assert.IsNotType(ex); + } + finally + { + AppDomain.Unload(sandbox); + } + } + + /// + /// Grant a narrow SqlClientPermission for a different server than the one used in Open(). + /// This proves that the permission demand checks the connection string content, not just + /// whether any SqlClientPermission is present. + /// + [Fact] + public void Open_WithMismatchedSqlClientPermission_ThrowsSecurityException() + { + var permissions = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None); + permissions.AddPermission(new System.Security.Permissions.SecurityPermission( + System.Security.Permissions.SecurityPermissionFlag.Execution)); + var sqlPerm = new SqlClientPermission(System.Security.Permissions.PermissionState.None); + sqlPerm.Add("Server=some_other_server;", "", KeyRestrictionBehavior.AllowOnly); + permissions.AddPermission(sqlPerm); + + var setup = new AppDomainSetup + { + ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + }; + + AppDomain sandbox = AppDomain.CreateDomain("PermissionTest_Mismatch", null, setup, permissions); + try + { + var ex = Record.Exception(() => sandbox.DoCallBack(OpenConnectionInSandbox)); + Assert.NotNull(ex); + // The demand fails because the granted permission ("some_other_server") doesn't + // cover the demanded permission ("will_not_resolve_12345"). This surfaces as + // SecurityException or FileLoadException (the CLR encounters a circular assembly + // load when constructing SecurityException with the custom permission type). + Assert.True( + ex is System.Security.SecurityException || ex is System.IO.FileLoadException, + $"Expected security failure, got {ex.GetType().FullName}: {ex.Message}"); + } + finally + { + AppDomain.Unload(sandbox); + } + } + + private static void OpenConnectionInSandbox() + { + using var connection = new SqlConnection("Server=will_not_resolve_12345;"); + connection.Open(); + } + } +} +#endif From 636a5e8963b7bf4b361205cd9f9e47594c5d6a66 Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 14:25:53 -0700 Subject: [PATCH 4/6] Remove old comment --- .../Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs index 25b40d30c0..4243e777ba 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs @@ -1271,7 +1271,6 @@ private void PoolCreateRequest(object state) { try { - // Don't specify any user options because there is no outer connection associated with the new connection newObj = CreateObject(owningObject: null, oldConnection: null); } catch From 8a94c0fb6d28768b383305f12344ce47e2055a75 Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 14:29:37 -0700 Subject: [PATCH 5/6] Update test namespace --- .../tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs index fbb486a3ae..0a252ec82f 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs @@ -7,7 +7,7 @@ using System.Data; using Xunit; -namespace Microsoft.Data.SqlClient.UnitTests.Microsoft.Data.SqlClient +namespace Microsoft.Data.SqlClient.UnitTests { /// /// Tests for Code Access Security (CAS) permission demands in SqlConnection. From be09e9ae2ad45470b9ee5e451723cbb40fd09dbe Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Wed, 6 May 2026 14:34:01 -0700 Subject: [PATCH 6/6] Add connect timeout to tests. --- .../tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs index 0a252ec82f..d69ca287d5 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/CasTest.cs @@ -65,7 +65,7 @@ public void Open_WithSqlClientPermission_DoesNotThrowSecurityException() permissions.AddPermission(new System.Security.Permissions.SecurityPermission( System.Security.Permissions.SecurityPermissionFlag.Execution)); var sqlPerm = new SqlClientPermission(System.Security.Permissions.PermissionState.None); - sqlPerm.Add("Server=will_not_resolve_12345;", "", KeyRestrictionBehavior.AllowOnly); + sqlPerm.Add("Server=will_not_resolve_12345;Connect Timeout=1;", "", KeyRestrictionBehavior.AllowOnly); permissions.AddPermission(sqlPerm); var setup = new AppDomainSetup @@ -127,7 +127,7 @@ public void Open_WithMismatchedSqlClientPermission_ThrowsSecurityException() private static void OpenConnectionInSandbox() { - using var connection = new SqlConnection("Server=will_not_resolve_12345;"); + using var connection = new SqlConnection("Server=will_not_resolve_12345;Connect Timeout=1;"); connection.Open(); } }