/// <summary>
        /// A convenience method to get a message as <see cref="TMessage"/> from the context.
        /// </summary>
        /// <param name="context">The context to get the message from.</param>
        /// <typeparam name="TMessage">The type of the message to try and get from the context.</typeparam>
        /// <returns>An instance of <see cref="TMessage"/> or null if the message was not of type <see cref="TMessage"/></returns>
        /// <exception cref="ArgumentNullException">The <see cref="context"/> object is null.</exception>
        public static TMessage MessageAs <TMessage>(this HandleMessageContext context) where TMessage : Message
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            return(context.Message as TMessage);
        }
        protected override async Task <bool> RunInnerAsync(HandleMessageContext context, Func <CancellationToken, Task <bool> > func, CancellationToken stoppingToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (func == null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            string lockKey = $"{context.Message.UniqueKey()}-{_lockSuffixKeyForHandler}";

            MessageLockResponse lockResponse = await _messageLock.TryAcquireLockAsync(lockKey, _timeout).ConfigureAwait(false);

            if (!lockResponse.DoIHaveExclusiveLock)
            {
                if (lockResponse.IsMessagePermanentlyLocked)
                {
                    _logger.LogDebug("Failed to acquire lock for message with key {MessageLockKey} as it is permanently locked.", lockKey);
                    return(RemoveTheMessageFromTheQueue);
                }

                _logger.LogDebug("Failed to acquire lock for message with key {MessageLockKey}; returning message to queue.", lockKey);
                return(LeaveItInTheQueue);
            }

            try
            {
                _logger.LogDebug("Acquired lock for message with key {MessageLockKey}.", lockKey);

                bool successfullyHandled = await func(stoppingToken).ConfigureAwait(false);

                if (successfullyHandled)
                {
                    await _messageLock.TryAcquireLockPermanentlyAsync(lockKey).ConfigureAwait(false);

                    _logger.LogDebug("Acquired permanent lock for message with key {MessageLockKey}.", lockKey);
                }

                return(successfullyHandled);
            }
            catch (Exception)
            {
                await _messageLock.ReleaseLockAsync(lockKey).ConfigureAwait(false);

                _logger.LogDebug("Released lock for message with key {MessageLockKey}.", lockKey);
                throw;
            }
        }
        protected override async Task <bool> RunInnerAsync(
            HandleMessageContext context,
            Func <CancellationToken, Task <bool> > func,
            CancellationToken stoppingToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            stoppingToken.ThrowIfCancellationRequested();

            var resolutionContext = new HandlerResolutionContext(context.QueueName);

            IHandlerAsync <T> handler = _handlerResolver(resolutionContext);

            return(await handler.Handle(context.MessageAs <T>()).ConfigureAwait(false));
        }