// -----------
        // Constructor
        // -----------

        internal SqlConnectionContainer(SqlConnectionContainerHashHelper hashHelper, string appDomainKey, bool useDefaults) {
            IntPtr hscp;
            Bid.NotificationsScopeEnter(out hscp, "<sc.SqlConnectionContainer|DEP> %d#, queue: '%ls'", ObjectID, hashHelper.Queue);

            bool setupCompleted = false;

            try {
                _hashHelper = hashHelper;
                string guid = null;

                // If default, queue name is not present on hashHelper at this point - so we need to 
                // generate one and complete initialization.
                if (useDefaults) {
                    guid = Guid.NewGuid().ToString();
                    _queue = SQL.SqlNotificationServiceDefault+"-"+guid;
                    _hashHelper.ConnectionStringBuilder.ApplicationName = _queue; // Used by cleanup sproc.
                }
                else {
                    _queue = _hashHelper.Queue;
                }

#if DEBUG
                SqlConnectionString connectionStringOptions = new SqlConnectionString(_hashHelper.ConnectionStringBuilder.ConnectionString);
                Bid.NotificationsTrace("<sc.SqlConnectionContainer|DEP> Modified connection string: '%ls'\n", connectionStringOptions.UsersConnectionStringForTrace());
#endif

                // Always use ConnectionStringBuilder since in default case it is different from the 
                // connection string used in the hashHelper.
                _con = new SqlConnection(_hashHelper.ConnectionStringBuilder.ConnectionString); // Create connection and open.

                // Assert permission for this particular connection string since it differs from the user passed string
                // which we have already demanded upon.  
                SqlConnectionString connStringObj = (SqlConnectionString) _con.ConnectionOptions;
                connStringObj.CreatePermissionSet().Assert();
                if (connStringObj.LocalDBInstance != null ) {                                
                    // If it is LocalDB, we demanded LocalDB permissions too
                    LocalDBAPI.AssertLocalDBPermissions();
                }
                _con.Open();

                _cachedServer = _con.DataSource; // SQL BU DT 390531.

                if (!_con.IsYukonOrNewer) { // After open, verify Yukon or later.
                    throw SQL.NotificationsRequireYukon();
                }

                if (hashHelper.Identity != null) {  
                    // For now, DbConnectionPoolIdentity does not cache WindowsIdentity.
                    // That means for every container creation, we create a WindowsIdentity twice.
                    // We may want to improve this.
                    _windowsIdentity = DbConnectionPoolIdentity.GetCurrentWindowsIdentity();
                }

                _escapedQueueName      = SqlConnection.FixupDatabaseTransactionName(_queue); // Properly escape to prevent SQL Injection.
                _appDomainKeyHash      = new Dictionary<string, int>(); // Dictionary stores the Start/Stop refcount per AppDomain for this container.
                _com                   = new SqlCommand();
                _com.Connection        = _con;

                // SQL BU DT 391534 - determine if broker is enabled on current database.
                _com.CommandText = "select is_broker_enabled from sys.databases where database_id=db_id()";

                if (!(bool) _com.ExecuteScalar()) {
                    throw SQL.SqlDependencyDatabaseBrokerDisabled();
                }

                _conversationGuidParam = new SqlParameter("@p1", SqlDbType.UniqueIdentifier);
                _timeoutParam          = new SqlParameter("@p2", SqlDbType.Int);
                _timeoutParam.Value    = 0; // Timeout set to 0 for initial [....] query.
                _com.Parameters.Add(_timeoutParam);

                setupCompleted = true;
                // connection with the server has been setup - from this point use TearDownAndDispose() in case of error

                // Create standard query.
                _receiveQuery = "WAITFOR(RECEIVE TOP (1) message_type_name, conversation_handle, cast(message_body AS XML) as message_body from " + _escapedQueueName + "), TIMEOUT @p2;";

                // Create queue, service, [....] query, and async query on user thread to ensure proper
                // init prior to return.  

                if (useDefaults) { // Only create if user did not specify service & database.
                    _sprocName = SqlConnection.FixupDatabaseTransactionName(SQL.SqlNotificationStoredProcedureDefault+"-"+guid);
                    CreateQueueAndService(false); // Fail if we cannot create service, queue, etc.
                }
                else {
                    // Continue query setup.
                    _com.CommandText      = _receiveQuery;
                    _endConversationQuery = "END CONVERSATION @p1; ";
                    _concatQuery          = _endConversationQuery + _receiveQuery;
                }

                bool ignored = false;
                IncrementStartCount(appDomainKey, out ignored);
                // Query synchronously once to ensure everything is working correctly.
                // We want the exception to occur on start to immediately inform caller.
                SynchronouslyQueryServiceBrokerQueue();
                _timeoutParam.Value = _defaultWaitforTimeout; // [....] successful, extend timeout to 60 seconds.
                AsynchronouslyQueryServiceBrokerQueue();
            }
            catch (Exception e) {
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw;
                }

                ADP.TraceExceptionWithoutRethrow(e); // Discard failure, but trace for now.
                if (setupCompleted) {
                    // Be sure to drop service & queue.  This may fail if create service & queue failed.
                    // This method will not drop unless we created or service & queue ref-count is 0.
                    TearDownAndDispose();
                }
                else {
                    // connection has not been fully setup yet - cannot use TearDownAndDispose();
                    // we have to dispose the command and the connection to avoid connection leaks (until GC collects them).
                    if (_com != null) {
                        _com.Dispose();
                        _com = null;
                    }
                    if (_con != null) {
                        _con.Dispose();
                        _con = null;
                    }

                }
                throw;
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }
 private static SqlConnectionContainerHashHelper GetHashHelper(string connectionString, out SqlConnectionStringBuilder connectionStringBuilder, out DbConnectionPoolIdentity identity, out string user, string queue)
 {
     SqlConnectionContainerHashHelper helper;
     IntPtr ptr;
     Bid.NotificationsScopeEnter(out ptr, "<sc.SqlDependencyProcessDispatcher.GetHashString|DEP> %d#, queue: %ls", _staticInstance.ObjectID, queue);
     try
     {
         connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
         connectionStringBuilder.AsynchronousProcessing = true;
         connectionStringBuilder.Pooling = false;
         connectionStringBuilder.Enlist = false;
         if (queue != null)
         {
             connectionStringBuilder.ApplicationName = queue;
         }
         if (connectionStringBuilder.IntegratedSecurity)
         {
             identity = DbConnectionPoolIdentity.GetCurrent();
             user = null;
         }
         else
         {
             identity = null;
             user = connectionStringBuilder.UserID;
         }
         helper = new SqlConnectionContainerHashHelper(identity, connectionStringBuilder.ConnectionString, queue, connectionStringBuilder);
     }
     finally
     {
         Bid.ScopeLeave(ref ptr);
     }
     return helper;
 }