private IModel GetReceiverChannel(ExchangeParam exchangeParam, QueueParam queueParam,
                                          ushort prefetchCount)
        {
            return(_subscriberChannelDic.GetOrAdd(queueParam.Queue, key =>
            {
                var channel = _conn.CreateModel();

                queueParam.Queue = queueParam.Queue ?? "UndefinedQueueName";

                channel.QueueDeclare(queue: queueParam.Queue, durable: queueParam.Durable,
                                     exclusive: queueParam.Exclusive, autoDelete: queueParam.AutoDelete,
                                     arguments: queueParam.Arguments);

                if (exchangeParam != null)
                {
                    exchangeParam.Exchange = exchangeParam.Exchange ?? "UndefinedExchangeName";
                    channel.ExchangeDeclare(exchange: exchangeParam.Exchange,
                                            type: exchangeParam.Type.ToString().ToLower(),
                                            durable: exchangeParam.Durable, autoDelete: exchangeParam.AutoDelete,
                                            arguments: exchangeParam.Arguments);
                    channel.QueueBind(queue: queueParam.Queue, exchange: exchangeParam.Exchange,
                                      routingKey: queueParam.Queue);
                }

                channel.BasicQos(0, prefetchCount, false);
                return channel;
            }));
        }
        public void PublishMessage(string exchangeName, byte[] body)
        {
            var exchangeParam = new ExchangeParam {
                Exchange = exchangeName, Durable = false
            };

            using (var channel = CreatePublisherChannel(exchangeParam, null))
            {
                var routingKey = exchangeParam.Exchange;
                channel.BasicPublish(exchangeParam.Exchange, routingKey, null, body);
            }
        }
        public void SubscribeMessage <T>(string exchange, string queue, Action <T> handle, ushort prefetchCount = 10)
        {
            var exchangeParam = new ExchangeParam {
                Exchange = exchange, Durable = false
            };
            var queueParam = new QueueParam {
                Queue = queue, Durable = false
            };
            var channel = GetReceiverChannel(exchangeParam, queueParam, prefetchCount);

            ConsumeEvent(channel, handle, queueParam.Queue);
        }
        public void SubscribeEvent <T>(string exchange, string queue, Func <Action <T> > resolve, ushort prefetchCount = 10)
        {
            var exchangeParam = new ExchangeParam {
                Exchange = exchange
            };
            var queueParam = new QueueParam {
                Queue = queue
            };
            var channel = GetReceiverChannel(exchangeParam, queueParam, prefetchCount);

            ConsumeEvent(channel, resolve, queueParam.Queue);
        }
        private void ConsumeEvent <T>(IModel channel, Func <Action <T> > resolve, string queue)
        {
            var consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, ea) =>
            {
                Task.Run(() =>
                {
                    try
                    {
                        var msg = _serializer.Deserialize <T>(ea.Body);
                        resolve.Invoke()(msg);
                    }
                    catch (Exception ex)
                    {
                        var innermostEx = ex.GetInnestException();

                        var dlxName          = GetDeadLetterName(queue);
                        var dlxExchangeParam = new ExchangeParam {
                            Exchange = dlxName
                        };
                        var dlxQueueParam = new QueueParam {
                            Queue = dlxName
                        };

                        using (var deadLetterMsgChannel = CreatePublisherChannel(dlxExchangeParam, dlxQueueParam))
                        {
                            var properties        = deadLetterMsgChannel.CreateBasicProperties();
                            properties.Persistent = true;
                            var routingKey        = dlxExchangeParam.Exchange;

                            var dlx = new DeadLetterMsg
                            {
                                QueueName  = queue,
                                ExMsg      = innermostEx.Message,
                                ExStack    = innermostEx.StackTrace,
                                ThrowTime  = DateTimeOffset.Now,
                                BodyString = _serializer.BytesToString(ea.Body)
                            };

                            deadLetterMsgChannel.BasicPublish(dlxExchangeParam.Exchange, routingKey, properties,
                                                              _serializer.Serialize(dlx));
                        }
                    }
                    finally
                    {
                        channel.BasicAck(ea.DeliveryTag, false);
                    }
                });
            };
            channel.BasicConsume(queue: queue, autoAck: false, consumer: consumer);
        }
        public void ReceiveMessage <T>(Func <Action <T> > resolve, ushort prefetchCount = 10)
        {
            var messageName   = GetTypeName(typeof(T));
            var exchangeParam = new ExchangeParam {
                Exchange = messageName, Durable = false
            };
            var queueParam = new QueueParam {
                Queue = messageName, Durable = false
            };
            var channel = GetReceiverChannel(exchangeParam, queueParam, prefetchCount);

            ConsumeMessage(channel, resolve, messageName);
        }
        public void ReceiveEvent <T>(Func <Action <T> > resolve, ushort prefetchCount = 10)
        {
            var eventName     = GetTypeName(typeof(T));
            var exchangeParam = new ExchangeParam {
                Exchange = eventName
            };
            var queueParam = new QueueParam {
                Queue = eventName
            };
            var channel = GetReceiverChannel(exchangeParam, queueParam, prefetchCount);

            ConsumeEvent(channel, resolve, eventName);
        }
        public void PublishEvent(string exchangeName, byte[] body)
        {
            var exchangeParam = new ExchangeParam {
                Exchange = exchangeName
            };

            using (var channel = CreatePublisherChannel(exchangeParam, null))
            {
                var properties = channel.CreateBasicProperties();
                properties.Persistent = true;
                var routingKey = exchangeParam.Exchange;

                channel.BasicPublish(exchangeParam.Exchange, routingKey, properties, body);
            }
        }
        public void ListenMessage <T>(Action <T> handle, ushort prefetchCount = 10)
        {
            var exchangeName   = GetTypeName(typeof(T));
            var methodFullName =
                $"{handle.Method.ReflectedType?.FullName}.{handle.Method.Name}[{exchangeName}][{Guid.NewGuid()}]";

            var exchangeParam = new ExchangeParam {
                Exchange = exchangeName, Durable = false
            };
            var queueParam =
                new QueueParam {
                Queue = methodFullName, Durable = false, Exclusive = true, AutoDelete = true
            };
            var channel = GetReceiverChannel(exchangeParam, queueParam, prefetchCount);

            ConsumeMessage(channel, handle, queueParam.Queue);
        }
        public void RepublishDeadLetterEvent <T>(string deadLetterQueueName, ushort prefetchCount = 1)
        {
            var queueParam = new QueueParam {
                Queue = deadLetterQueueName
            };
            var channel = GetReceiverChannel(null, queueParam, prefetchCount);

            var consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var msg  = _serializer.Deserialize <DeadLetterMsg>(body);

                var republishExchangeParam =
                    new ExchangeParam {
                    Exchange = $"republish-{deadLetterQueueName}", Durable = true
                };
                var republishQueueParam =
                    new QueueParam {
                    Queue = FromDeadLetterName(deadLetterQueueName), Durable = true
                };
                using (var republishChannel = CreatePublisherChannel(republishExchangeParam, republishQueueParam))
                {
                    var properties = republishChannel.CreateBasicProperties();
                    properties.Persistent = true;
                    var routingKey = republishExchangeParam.Exchange;

                    var deadLetter = _serializer.FromString <T>(msg.BodyString);

                    republishChannel.BasicPublish(republishExchangeParam.Exchange, routingKey, properties,
                                                  _serializer.Serialize(deadLetter));
                }

                channel.BasicAck(ea.DeliveryTag, false);
            };
            channel.BasicConsume(queue: deadLetterQueueName, autoAck: false, consumer: consumer);
        }
        private IModel CreatePublisherChannel(ExchangeParam exchangeParam, QueueParam queueParam)
        {
            var channel = _conn.CreateModel();

            exchangeParam.Exchange = exchangeParam.Exchange ?? "UndefinedExchangeName";

            channel.ExchangeDeclare(exchange: exchangeParam.Exchange, type: exchangeParam.Type.ToString().ToLower(),
                                    durable: exchangeParam.Durable, autoDelete: exchangeParam.AutoDelete,
                                    arguments: exchangeParam.Arguments);

            if (queueParam == null)
            {
                return(channel);
            }

            queueParam.Queue = queueParam.Queue ?? "UndefinedQueueName";
            channel.QueueDeclare(queue: queueParam.Queue, durable: queueParam.Durable,
                                 exclusive: queueParam.Exclusive, autoDelete: queueParam.AutoDelete,
                                 arguments: queueParam.Arguments);
            channel.QueueBind(queue: queueParam.Queue, exchange: exchangeParam.Exchange,
                              routingKey: queueParam.Queue);

            return(channel);
        }