/// <summary>
        /// Opens new <see cref="Session"/> with specified <see cref="SessionConfiguration"/> asynchronously.
        /// </summary>
        /// <param name="configuration">The session configuration.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task representing the asynchronous operation.</returns>
        /// <sample><code>
        /// var ctSource = new CancellationTokenSource();
        /// using (var session = await domain.OpenSessionAsync(configuration, ctSource.Token)) {
        /// // work with persistent objects here
        /// }
        /// </code></sample>
        /// <seealso cref="Session"/>
        public Task <Session> OpenSessionAsync(SessionConfiguration configuration, CancellationToken cancellationToken = default)
        {
            ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration));

            SessionScope sessionScope = null;

            try {
                if (configuration.Supports(SessionOptions.AutoActivation))
                {
                    sessionScope = new SessionScope();
                }
                return(OpenSessionInternalAsync(configuration, null, sessionScope, cancellationToken));
            }
            catch {
                sessionScope?.Dispose();
                throw;
            }
        }
        internal async Task <Session> OpenSessionInternalAsync(SessionConfiguration configuration, StorageNode storageNode, SessionScope sessionScope, CancellationToken cancellationToken)
        {
            ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration));
            configuration.Lock(true);

            if (isDebugEventLoggingEnabled)
            {
                OrmLog.Debug(Strings.LogOpeningSessionX, configuration);
            }

            Session session;

            if (SingleConnection != null)
            {
                // Ensure that we check shared connection availability
                // and acquire connection atomically.
                lock (singleConnectionGuard) {
                    if (singleConnectionOwner != null)
                    {
                        throw new InvalidOperationException(string.Format(
                                                                Strings.ExSessionXStillUsesSingleAvailableConnection, singleConnectionOwner));
                    }
                    session = new Session(this, storageNode, configuration, false);
                    singleConnectionOwner = session;
                }
            }
            else
            {
                // DO NOT make session active right from constructor.
                // That would make session accessible for user before
                // connection become opened.
                session = new Session(this, storageNode, configuration, false);
                try {
                    await((SqlSessionHandler)session.Handler).OpenConnectionAsync(cancellationToken)
                    .ContinueWith(t => {
                        if (sessionScope != null)
                        {
                            session.AttachToScope(sessionScope);
                        }
                    }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously)
                    .ConfigureAwait(false);
                }
                catch (OperationCanceledException) {
                    await session.DisposeSafelyAsync().ConfigureAwait(false);

                    throw;
                }
            }
            NotifySessionOpen(session);
            return(session);
        }