//private string BuildInvocationFailureMessage(string methodName, object[] arguments)
    //{
    //	return string.Concat(new string[]
    //	{
    //		"Failed to invoke target method '",
    //		methodName,
    //		"' with argument types = [",
    //		StringUtils.CollectionToCommaDelimitedString<string>(this.GetArgumentTypes(arguments)),
    //		"], values = [",
    //		StringUtils.CollectionToCommaDelimitedString<object>(arguments),
    //		"]"
    //	});
    //}
    //private System.Collections.Generic.List<string> GetArgumentTypes(object[] arguments)
    //{
    //	System.Collections.Generic.List<string> list = new System.Collections.Generic.List<string>();
    //	if (arguments != null)
    //	{
    //		for (int i = 0; i < arguments.Length; i++)
    //		{
    //			list.Add(arguments[i].GetType().ToString());
    //		}
    //	}
    //	return list;
    //}

    protected virtual void HandleResult(AmqpBasedRoute replyRoute, List <object> responses)
    {
        if (replyRoute != null)
        {
            this._queueClient.BatchPublish(exchangeName: replyRoute.ExchangeName, routingKey: replyRoute.RoutingKey, contentList: responses);
        }
    }
    public QueuedWorkflowMessageProcessingWorker(IQueueClient queueClient, object listenerObject, MethodInfo listenerMethod, QueuedTransition queuedTransition, QueuedTransition nextQueuedTransition, bool createZombieQueues)
    {
        Contract.Requires(queueClient.IsNotNull(), "No queueClient specified: Either specify a non-null value for the 'queueClient' constructor argument.");
        Contract.Requires(listenerObject.IsNotNull(), "No listenerObject specified: Either specify a non-null value for the 'listenerObject' constructor argument.");
        Contract.Requires(listenerMethod.IsNotNull(), "No listenerMethod specified: Either specify a non-null value for the 'listenerMethod' constructor argument.");
        this._queueClient    = queueClient;
        this._listenerObject = listenerObject;
        this._listenerMethod = listenerMethod;


        Type inType  = this._listenerMethod.GetUniqueAndExpectedInputParameterType();
        Type outType = this._listenerMethod.GetReturnValueType();

        if (outType == typeof(void) || outType == typeof(Task))
        {
            this._canUseRequestAsResponse = true;
        }
        else
        {
            this._canUseRequestAsResponse = outType.IsAssignableFrom(inType);
        }

        //Receive Route é usada para garantir a criação da rota no RabbitMQ
        this.ReceiveRoute = new AmqpBasedRoute()
        {
            ExchangeName = queuedTransition.ExchangeName,                   //Criando ExchangeName Default
            QueueName    = queuedTransition.LogicalQueueName + ".Process",  //Queue de recebimento (Fila Principal)
            RoutingKey   = queuedTransition.BuildRoutingKey()               //Binding Entre a ExchangeName e a Fila
        };
        this.ReceiveRoute.EnsureAll(this._queueClient);

        if (createZombieQueues)
        {
            //Filas Zombie não precisam ser armazenadas em variáveis, só precisam ser configuradas
            //corretamente no RabbitMQ
            AmqpBasedRoute zombieConfiguration = new AmqpBasedRoute()
            {
                ExchangeName = this.ReceiveRoute.ExchangeName,
                QueueName    = queuedTransition.LogicalQueueName + ".Zombie",
                RoutingKey   = this.ReceiveRoute.RoutingKey
            };
            zombieConfiguration.EnsureAll(this._queueClient);
        }

        //Caso não seja um passo final, é necessário armazenar e tratar as respostas para o próximo step
        if (nextQueuedTransition != null)
        {
            this._successResponseRoute = new AmqpBasedRoute()
            {
                QueueName    = nextQueuedTransition.LogicalQueueName + ".Process",
                ExchangeName = nextQueuedTransition.ExchangeName,
                RoutingKey   = nextQueuedTransition.BuildRoutingKey(),
            };
            this._successResponseRoute.EnsureAll(this._queueClient);
        }

        this._errorFlowStrategy = queuedTransition.ErrorFlowStrategy;
        //Nesse passo as estratégias são usadas para configurar o comportamento adequado para falhas
        if (this._errorFlowStrategy == ExceptionStrategy.SendToErrorQueue)
        {
            //Se ao encontrar um erro, é necessário enviar para a fila de erro, todo o pipe de erro é criado
            //isso conta com a criação da fila, e dos bindings no RabbitMQ
            this._failureResponseRoute = new AmqpBasedRoute()
            {
                QueueName    = queuedTransition.LogicalQueueName + ".Failure",
                ExchangeName = this.ReceiveRoute.ExchangeName,
                RoutingKey   = queuedTransition.BuildFailureRoutingKey()
            };
            this._failureResponseRoute.EnsureAll(this._queueClient);
        }
        else if (this._errorFlowStrategy == ExceptionStrategy.Requeue)
        {
            //Nesse caso, ao gerar um erro na fila a mensagem volta para a fila, portanto
            //a rota usada é escolhida como a mesma rota de recebimento, forçando um requeue
            this._failureResponseRoute = this.ReceiveRoute;
        }
        else if (this._errorFlowStrategy == ExceptionStrategy.SendToNextStepQueue)
        {
            //Nesse caso temos a possibilidade de continuar o fluxo, mesmo que uma
            //exceção seja lançada.
            if (this._successResponseRoute == null)
            {
                throw new InvalidOperationException("The ErrorFlowStrategy property cannot be setted with SendToNextStepQueue value when current step is a final step.");
            }
            this._failureResponseRoute = this._successResponseRoute;
        }
    }