public async Task <IListener> CreateAsync(CancellationToken cancellationToken)
        {
            // Note that these clients are intentionally for the storage account rather than for the dashboard account.
            // We use the storage, not dashboard, account for the blob receipt container and blob trigger queues.
            IStorageQueueClient primaryQueueClient = _hostAccount.CreateQueueClient();
            IStorageBlobClient  primaryBlobClient  = _hostAccount.CreateBlobClient();

            // Important: We're using the storage account of the function target here, which is the account that the
            // function the listener is for is targeting. This is the account that will be used
            // to read the trigger blob.
            IStorageBlobClient  targetBlobClient  = _dataAccount.CreateBlobClient();
            IStorageQueueClient targetQueueClient = _dataAccount.CreateQueueClient();

            string hostId = await _hostIdProvider.GetHostIdAsync(cancellationToken);

            string        hostBlobTriggerQueueName = HostQueueNames.GetHostBlobTriggerQueueName(hostId);
            IStorageQueue hostBlobTriggerQueue     = primaryQueueClient.GetQueueReference(hostBlobTriggerQueueName);

            SharedQueueWatcher sharedQueueWatcher = _sharedContextProvider.GetOrCreateInstance <SharedQueueWatcher>(
                new SharedQueueWatcherFactory(_messageEnqueuedWatcherSetter));

            SharedBlobListener sharedBlobListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobListener>(
                new SharedBlobListenerFactory(hostId, _hostAccount, _exceptionHandler, _blobWrittenWatcherSetter));

            // Register the blob container we wish to monitor with the shared blob listener.
            await RegisterWithSharedBlobListenerAsync(hostId, sharedBlobListener, primaryBlobClient,
                                                      hostBlobTriggerQueue, sharedQueueWatcher, cancellationToken);

            // Create a "bridge" listener that will monitor the blob
            // notification queue and dispatch to the target job function.
            SharedBlobQueueListener sharedBlobQueueListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobQueueListener>(
                new SharedBlobQueueListenerFactory(_hostAccount, sharedQueueWatcher, hostBlobTriggerQueue,
                                                   _queueConfiguration, _exceptionHandler, _trace, _loggerFactory, sharedBlobListener.BlobWritterWatcher));
            var queueListener = new BlobListener(sharedBlobQueueListener);

            // determine which client to use for the poison queue
            // by default this should target the same storage account
            // as the blob container we're monitoring
            var poisonQueueClient = targetQueueClient;

            if (_dataAccount.Type != StorageAccountType.GeneralPurpose ||
                _blobsConfiguration.CentralizedPoisonQueue)
            {
                // use the primary storage account if the centralize flag is true,
                // or if the target storage account doesn't support queues
                poisonQueueClient = primaryQueueClient;
            }

            // Register our function with the shared blob queue listener
            RegisterWithSharedBlobQueueListenerAsync(sharedBlobQueueListener, targetBlobClient, poisonQueueClient);

            // check a flag in the shared context to see if we've created the singleton
            // shared blob listener in this host instance
            object singletonListenerCreated = false;

            if (!_sharedContextProvider.TryGetValue(SingletonBlobListenerScopeId, out singletonListenerCreated))
            {
                // Create a singleton shared blob listener, since we only
                // want a single instance of the blob poll/scan logic to be running
                // across host instances
                var singletonBlobListener = _singletonManager.CreateHostSingletonListener(
                    new BlobListener(sharedBlobListener), SingletonBlobListenerScopeId);
                _sharedContextProvider.SetValue(SingletonBlobListenerScopeId, true);

                return(new CompositeListener(singletonBlobListener, queueListener));
            }
            else
            {
                // We've already created the singleton blob listener
                // so just return our queue listener. Note that while we want the
                // blob scan to be singleton, the shared queue listener needs to run
                // on ALL instances so load can be scaled out
                return(queueListener);
            }
        }