diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs index 10fd4e794..9e8cbf7e2 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs @@ -243,20 +243,25 @@ private void OpenWithCheckAndNotification(string checkQueryString, DbConnectionA var connectionChecked = false; var restoreTriggered = false; var accessors = connectionAccessorEx.Accessors; + var session = NotificationSession; while (!connectionChecked) { - SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpening( + accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered), session); underlyingConnection.Open(); try { - SqlHelper.NotifyConnectionInitializing(accessors, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionInitializing( + accessors, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered), session); using (var command = underlyingConnection.CreateCommand()) { command.CommandText = checkQueryString; _ = command.ExecuteNonQuery(); } connectionChecked = true; - SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpened( + accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered), session); } catch (Exception exception) { - SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpeningFailed( + accessors, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered), session); if (InternalHelpers.ShouldRetryOn(exception)) { if (restoreTriggered) { throw; @@ -311,17 +316,27 @@ private async Task OpenWithCheckAndNotificationAsync(string checkQueryString, var restoreTriggered = false; var accessors = connectionAccessorEx.Accessors; + var session = NotificationSession; while (!connectionChecked) { cancellationToken.ThrowIfCancellationRequested(); - await SqlHelper.NotifyConnectionOpeningAsync(accessors, - UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) + await SqlHelper.NotifyConnectionOpeningAsync( + accessors, + UnderlyingConnection, + (!connectionChecked && !restoreTriggered), + cancellationToken, + session) .ConfigureAwaitFalse(); await underlyingConnection.OpenAsync(cancellationToken).ConfigureAwaitFalse(); try { - await SqlHelper.NotifyConnectionInitializingAsync(accessors, - UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered), cancellationToken) + await SqlHelper.NotifyConnectionInitializingAsync( + accessors, + UnderlyingConnection, + checkQueryString, + (!connectionChecked && !restoreTriggered), + cancellationToken, + session) .ConfigureAwaitFalse(); var command = underlyingConnection.CreateCommand(); @@ -330,12 +345,22 @@ await SqlHelper.NotifyConnectionInitializingAsync(accessors, _ = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwaitFalse(); } connectionChecked = true; - await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) + await SqlHelper.NotifyConnectionOpenedAsync( + accessors, + UnderlyingConnection, + (!connectionChecked && !restoreTriggered), + cancellationToken, + session) .ConfigureAwaitFalse(); } catch (Exception exception) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, - UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered), cancellationToken) + await SqlHelper.NotifyConnectionOpeningFailedAsync( + accessors, + UnderlyingConnection, + exception, + (!connectionChecked && !restoreTriggered), + cancellationToken, + session) .ConfigureAwaitFalse(); if (InternalHelpers.ShouldRetryOn(exception)) { diff --git a/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs b/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs index 41d42876b..c00132423 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs @@ -26,16 +26,19 @@ public class MyConnectionAccessor : DbConnectionAccessor public int ConnectionInitializationCounter; public int ConnectionOpenedCounter; public int ConnectionOpeningFailedCounter; + public Session LastSession; public override void ConnectionOpening(ConnectionEventData eventData) { instanceMarker = UniqueInstanceIdentifier; ConnectionOpeningCounter++; + LastSession = eventData.Session; } public override void ConnectionInitialization(ConnectionInitEventData eventData) { ConnectionInitializationCounter++; + LastSession = eventData.Session; if (instanceMarker != UniqueInstanceIdentifier) { throw new Exception("Not the same instance"); } @@ -44,6 +47,7 @@ public override void ConnectionInitialization(ConnectionInitEventData eventData) public override void ConnectionOpened(ConnectionEventData eventData) { ConnectionOpenedCounter++; + LastSession = eventData.Session; if (instanceMarker != UniqueInstanceIdentifier) { throw new Exception("Not the same instance"); } @@ -52,6 +56,7 @@ public override void ConnectionOpened(ConnectionEventData eventData) public override void ConnectionOpeningFailed(ConnectionErrorEventData eventData) { ConnectionOpeningFailedCounter++; + LastSession = eventData.Session; if (instanceMarker != UniqueInstanceIdentifier) { throw new Exception("Not the same instance"); } @@ -209,6 +214,7 @@ public void SessionConnectionAccessorsTest() var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.LastSession, Is.SameAs(session)); first = accessorInstance.UniqueInstanceIdentifier; } @@ -220,6 +226,7 @@ public void SessionConnectionAccessorsTest() var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.LastSession, Is.SameAs(session)); second = accessorInstance.UniqueInstanceIdentifier; } @@ -242,6 +249,7 @@ public async Task SessionConnectionAccessorsAsyncTest() var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.LastSession, Is.SameAs(session)); first = accessorInstance.UniqueInstanceIdentifier; } @@ -253,6 +261,7 @@ public async Task SessionConnectionAccessorsAsyncTest() var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.LastSession, Is.SameAs(session)); second = accessorInstance.UniqueInstanceIdentifier; } diff --git a/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs index 4f1d7f418..b0a0adc2c 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs @@ -4,7 +4,6 @@ using System; using System.Data.Common; -using Xtensive.Core; namespace Xtensive.Orm { @@ -18,8 +17,12 @@ public class ConnectionErrorEventData : ConnectionEventData /// public Exception Exception { get; } - public ConnectionErrorEventData(Exception exception, DbConnection connection, bool reconnect = false) - : base(connection, reconnect) + public ConnectionErrorEventData( + Exception exception, + DbConnection connection, + bool reconnect = false, + Session session = null) + : base(connection, reconnect, session) { ArgumentNullException.ThrowIfNull(exception); Exception = exception; diff --git a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs index 58422d500..3e3182758 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs @@ -4,7 +4,6 @@ using System; using System.Data.Common; -using Xtensive.Core; namespace Xtensive.Orm { @@ -23,11 +22,19 @@ public class ConnectionEventData /// public bool Reconnect { get; } - public ConnectionEventData(DbConnection connection, bool reconnect = false) + /// + /// The that owns the open operation, if the connection is being + /// opened on behalf of a session. for domain/driver opens + /// that are not session-scoped. + /// + public Session Session { get; } + + public ConnectionEventData(DbConnection connection, bool reconnect = false, Session session = null) { ArgumentNullException.ThrowIfNull(connection); Connection = connection; Reconnect = reconnect; + Session = session; } } } diff --git a/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs index 012ec4ff2..f83ba173f 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs @@ -2,8 +2,8 @@ // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. +using System; using System.Data.Common; -using Xtensive.Core; namespace Xtensive.Orm { @@ -17,8 +17,12 @@ public class ConnectionInitEventData : ConnectionEventData /// public string InitializationScript { get; } - public ConnectionInitEventData(string initializationScript, DbConnection connection, bool reconnect = false) - : base(connection, reconnect) + public ConnectionInitEventData( + string initializationScript, + DbConnection connection, + bool reconnect = false, + Session session = null) + : base(connection, reconnect, session) { ArgumentException.ThrowIfNullOrEmpty(initializationScript); InitializationScript = initializationScript; diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs index 8ca808353..373a03283 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs @@ -81,10 +81,10 @@ public void OpenConnection(Session session, SqlConnection connection) try { if (!string.IsNullOrEmpty(script)) { - connection.OpenAndInitialize(script); + connection.OpenAndInitialize(script, session); } else { - connection.Open(); + connection.Open(session); } } catch (Exception exception) { @@ -106,10 +106,10 @@ public async Task OpenConnectionAsync(Session session, SqlConnection connection, try { if (!string.IsNullOrEmpty(script)) { - await connection.OpenAndInitializeAsync(script, cancellationToken).ConfigureAwaitFalse(); + await connection.OpenAndInitializeAsync(script, session, cancellationToken).ConfigureAwaitFalse(); } else { - await connection.OpenAsync(cancellationToken).ConfigureAwaitFalse(); + await connection.OpenAsync(session, cancellationToken).ConfigureAwaitFalse(); } } catch (OperationCanceledException) { diff --git a/Orm/Xtensive.Orm/Sql/SqlConnection.cs b/Orm/Xtensive.Orm/Sql/SqlConnection.cs index b6f82511e..8aa18fd42 100644 --- a/Orm/Xtensive.Orm/Sql/SqlConnection.cs +++ b/Orm/Xtensive.Orm/Sql/SqlConnection.cs @@ -25,6 +25,7 @@ public abstract class SqlConnection : SqlDriverBound, private ConnectionInfo connectionInfo; private IExtensionCollection extensions; private bool isDisposed; + private Session notificationSession; [MethodImpl(MethodImplOptions.AggressiveInlining)] protected void EnsureIsNotDisposed() @@ -86,6 +87,13 @@ public int? CommandTimeout /// public ConnectionState State => isDisposed ? ConnectionState.Closed : UnderlyingConnection.State; + /// + /// Session bound for the in-flight open notification callbacks, if any. + /// Set by the session-aware / + /// overloads. + /// + protected Session NotificationSession => notificationSession; + /// /// Creates and returns a object associated with the current connection. /// @@ -155,6 +163,22 @@ public virtual ICharacterLargeObject CreateCharacterLargeObject() => public virtual IBinaryLargeObject CreateBinaryLargeObject() => throw SqlHelper.NotSupported(ServerFeatures.LargeObjects); + /// + /// Opens the connection on behalf of so connection-accessor + /// notifications carry that session. + /// + public void Open(Session session) + { + ArgumentNullException.ThrowIfNull(session); + notificationSession = session; + try { + Open(); + } + finally { + notificationSession = null; + } + } + /// /// Opens the connection. /// @@ -167,18 +191,35 @@ public virtual void Open() } else { var accessors = connectionAccessorEx.Accessors; - SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection); + var session = notificationSession; + SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection, session: session); try { UnderlyingConnection.Open(); - SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection, session: session); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex, session: session); throw; } } } + /// + /// Opens the connection on behalf of and initializes it with given script + /// so connection-accessor notifications carry that session. + /// + public void OpenAndInitialize(string initializationScript, Session session) + { + ArgumentNullException.ThrowIfNull(session); + notificationSession = session; + try { + OpenAndInitialize(initializationScript); + } + finally { + notificationSession = null; + } + } + /// /// Opens the connection and initialize it with given script. /// @@ -199,26 +240,45 @@ public virtual void OpenAndInitialize(string initializationScript) } else { var accessors = connectionAccessorEx.Accessors; - SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection); + var session = notificationSession; + SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection, session: session); try { UnderlyingConnection.Open(); if (string.IsNullOrEmpty(initializationScript)) { - SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection, session: session); return; } - SqlHelper.NotifyConnectionInitializing(accessors, UnderlyingConnection, initializationScript); + SqlHelper.NotifyConnectionInitializing( + accessors, UnderlyingConnection, initializationScript, session: session); using var command = UnderlyingConnection.CreateCommand(); command.CommandText = initializationScript; _ = command.ExecuteNonQuery(); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection, session: session); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex, session: session); throw; } } } + /// + /// Opens the connection asynchronously on behalf of so + /// connection-accessor notifications carry that session. + /// + public async Task OpenAsync(Session session, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(session); + notificationSession = session; + try { + await OpenAsync(cancellationToken).ConfigureAwaitFalse(); + } + finally { + notificationSession = null; + } + } + /// /// Opens the connection asynchronously. /// @@ -236,18 +296,39 @@ public virtual async Task OpenAsync(CancellationToken cancellationToken) } else { var accessors = connectionAccessorEx.Accessors; - await SqlHelper.NotifyConnectionOpeningAsync(accessors, UnderlyingConnection, false, cancellationToken); + var session = notificationSession; + await SqlHelper.NotifyConnectionOpeningAsync( + accessors, UnderlyingConnection, false, cancellationToken, session); try { await UnderlyingConnection.OpenAsync(cancellationToken); - await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, cancellationToken); + await SqlHelper.NotifyConnectionOpenedAsync( + accessors, UnderlyingConnection, false, cancellationToken, session); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, cancellationToken); + await SqlHelper.NotifyConnectionOpeningFailedAsync( + accessors, UnderlyingConnection, ex, false, cancellationToken, session); throw; } } } + /// + /// Opens the connection asynchronously on behalf of and initializes it + /// with given script so connection-accessor notifications carry that session. + /// + public async Task OpenAndInitializeAsync( + string initializationScript, Session session, CancellationToken token = default) + { + ArgumentNullException.ThrowIfNull(session); + notificationSession = session; + try { + await OpenAndInitializeAsync(initializationScript, token).ConfigureAwaitFalse(); + } + finally { + notificationSession = null; + } + } + /// /// Opens the connection and initialize it with given script asynchronously. /// @@ -281,29 +362,36 @@ public virtual async Task OpenAndInitializeAsync(string initializationScript, Ca } else { var accessors = connectionAccessorEx.Accessors; - await SqlHelper.NotifyConnectionOpeningAsync(accessors, UnderlyingConnection, false, token); + var session = notificationSession; + await SqlHelper.NotifyConnectionOpeningAsync( + accessors, UnderlyingConnection, false, token, session); await UnderlyingConnection.OpenAsync(token).ConfigureAwaitFalse(); if (string.IsNullOrEmpty(initializationScript)) { - await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, token); + await SqlHelper.NotifyConnectionOpenedAsync( + accessors, UnderlyingConnection, false, token, session); return; } try { - await SqlHelper.NotifyConnectionInitializingAsync(accessors, UnderlyingConnection, initializationScript, false, token); + await SqlHelper.NotifyConnectionInitializingAsync( + accessors, UnderlyingConnection, initializationScript, false, token, session); var command = UnderlyingConnection.CreateCommand(); await using (command.ConfigureAwaitFalse()) { command.CommandText = initializationScript; _ = await command.ExecuteNonQueryAsync(token).ConfigureAwaitFalse(); } - await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, token); + await SqlHelper.NotifyConnectionOpenedAsync( + accessors, UnderlyingConnection, false, token, session); } catch (OperationCanceledException ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, token); + await SqlHelper.NotifyConnectionOpeningFailedAsync( + accessors, UnderlyingConnection, ex, false, token, session); await UnderlyingConnection.CloseAsync().ConfigureAwaitFalse(); throw; } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, token); + await SqlHelper.NotifyConnectionOpeningFailedAsync( + accessors, UnderlyingConnection, ex, false, token, session); throw; } } diff --git a/Orm/Xtensive.Orm/Sql/SqlHelper.cs b/Orm/Xtensive.Orm/Sql/SqlHelper.cs index c24da3488..535733ba5 100644 --- a/Orm/Xtensive.Orm/Sql/SqlHelper.cs +++ b/Orm/Xtensive.Orm/Sql/SqlHelper.cs @@ -562,11 +562,14 @@ public static NotSupportedException NotSupported(ServerFeatures feature) /// if event happened on attemp to restore connection, otherwise . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpening( - IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false) + IEnumerable connectionAccessors, + DbConnection connection, + bool reconnect = false, + Session session = null) { ConnectionEventData eventData = null; foreach (var accessor in connectionAccessors) { - accessor.ConnectionOpening(eventData ??= new ConnectionEventData(connection, reconnect)); + accessor.ConnectionOpening(eventData ??= new ConnectionEventData(connection, reconnect, session)); } } @@ -578,15 +581,20 @@ public static void NotifyConnectionOpening( /// The connection that is opening. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. + /// Session that owns the open, if any. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionOpeningAsync( - IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, + DbConnection connection, + bool reconnect = false, + CancellationToken token = default, + Session session = null) { ConnectionEventData eventData = null; foreach (var accessor in connectionAccessors) { await accessor.ConnectionOpeningAsync( - eventData ??= new ConnectionEventData(connection, reconnect), token) + eventData ??= new ConnectionEventData(connection, reconnect, session), token) .ConfigureAwaitFalse(); } } @@ -599,12 +607,18 @@ await accessor.ConnectionOpeningAsync( /// Opened but not initialized connection /// The script that will run to initialize connection /// if event happened on attemp to restore connection, otherwise . + /// Session that owns the open, if any. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionInitializing( - IEnumerable connectionAccessors, DbConnection connection, string initializationScript, bool reconnect = false) + IEnumerable connectionAccessors, + DbConnection connection, + string initializationScript, + bool reconnect = false, + Session session = null) { foreach (var accessor in connectionAccessors) { - accessor.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect)); + accessor.ConnectionInitialization( + new ConnectionInitEventData(initializationScript, connection, reconnect, session)); } } @@ -617,15 +631,20 @@ public static void NotifyConnectionInitializing( /// The script that will run to initialize connection /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. + /// Session that owns the open, if any. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionInitializingAsync( - IEnumerable connectionAccessors, DbConnection connection, string initializationScript, - bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, + DbConnection connection, + string initializationScript, + bool reconnect = false, + CancellationToken token = default, + Session session = null) { foreach (var accessor in connectionAccessors) { await accessor.ConnectionInitializationAsync( - new ConnectionInitEventData(initializationScript, connection, reconnect), token) + new ConnectionInitEventData(initializationScript, connection, reconnect, session), token) .ConfigureAwaitFalse(); } } @@ -637,12 +656,16 @@ await accessor.ConnectionInitializationAsync( /// The accessors that should be notified. /// The connection that is completely opened and initialized. /// if event happened on attemp to restore connection, otherwise . + /// Session that owns the open, if any. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpened( - IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false) + IEnumerable connectionAccessors, + DbConnection connection, + bool reconnect = false, + Session session = null) { foreach (var accessor in connectionAccessors) { - accessor.ConnectionOpened(new ConnectionEventData(connection, reconnect)); + accessor.ConnectionOpened(new ConnectionEventData(connection, reconnect, session)); } } @@ -654,14 +677,19 @@ public static void NotifyConnectionOpened( /// The connection that is completely opened and initialized. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. + /// Session that owns the open, if any. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionOpenedAsync( - IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, + DbConnection connection, + bool reconnect = false, + CancellationToken token = default, + Session session = null) { foreach (var accessor in connectionAccessors) { await accessor.ConnectionOpenedAsync( - new ConnectionEventData(connection, reconnect), token) + new ConnectionEventData(connection, reconnect, session), token) .ConfigureAwaitFalse(); } } @@ -674,12 +702,17 @@ await accessor.ConnectionOpenedAsync( /// Connection that failed to be opened or properly initialized. /// The exception which appeared. /// if event happened on attemp to restore connection, otherwise . + /// Session that owns the open, if any. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpeningFailed( - IEnumerable connectionAccessors, DbConnection connection, Exception exception, bool reconnect = false) + IEnumerable connectionAccessors, + DbConnection connection, + Exception exception, + bool reconnect = false, + Session session = null) { foreach (var accessor in connectionAccessors) { - accessor.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect)); + accessor.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect, session)); } } @@ -692,15 +725,20 @@ public static void NotifyConnectionOpeningFailed( /// The exception which appeared. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. + /// Session that owns the open, if any. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionOpeningFailedAsync( - IEnumerable connectionAccessors, DbConnection connection, Exception exception, - bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, + DbConnection connection, + Exception exception, + bool reconnect = false, + CancellationToken token = default, + Session session = null) { foreach (var accessor in connectionAccessors) { await accessor.ConnectionOpeningFailedAsync( - new ConnectionErrorEventData(exception, connection, reconnect), token) + new ConnectionErrorEventData(exception, connection, reconnect, session), token) .ConfigureAwaitFalse(); } }