/// <summary>
        /// Pushes a message to a queue
        /// </summary>
        public async Task <HorseResult> PushJson(string queue, object jsonObject, string messageId, bool waitAcknowledge,
                                                 IEnumerable <KeyValuePair <string, string> > messageHeaders = null)
        {
            TypeDeliveryDescriptor descriptor = _client.DeliveryContainer.GetDescriptor(jsonObject.GetType());
            HorseMessage           message    = descriptor.CreateMessage(MessageType.QueueMessage, queue, 0);

            if (!string.IsNullOrEmpty(messageId))
            {
                message.SetMessageId(messageId);
            }

            message.WaitResponse = waitAcknowledge;

            if (messageHeaders != null)
            {
                foreach (KeyValuePair <string, string> pair in messageHeaders)
                {
                    message.AddHeader(pair.Key, pair.Value);
                }
            }

            message.Serialize(jsonObject, _client.JsonSerializer);

            if (string.IsNullOrEmpty(message.MessageId) && waitAcknowledge)
            {
                message.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            return(await _client.WaitResponse(message, waitAcknowledge));
        }
        /// <summary>
        /// Publishes a JSON object to a router
        /// </summary>
        public async Task <HorseResult> PublishJson(string routerName,
                                                    object model,
                                                    string messageId        = null,
                                                    bool waitForAcknowledge = false,
                                                    ushort?contentType      = null,
                                                    IEnumerable <KeyValuePair <string, string> > messageHeaders = null)
        {
            TypeDeliveryDescriptor descriptor = _client.DeliveryContainer.GetDescriptor(model.GetType());
            HorseMessage           message    = descriptor.CreateMessage(MessageType.Router, routerName, contentType);

            if (!string.IsNullOrEmpty(messageId))
            {
                message.SetMessageId(messageId);
            }
            else
            {
                message.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            message.WaitResponse = waitForAcknowledge;
            message.Serialize(model, _client.JsonSerializer);

            if (messageHeaders != null)
            {
                foreach (KeyValuePair <string, string> pair in messageHeaders)
                {
                    message.AddHeader(pair.Key, pair.Value);
                }
            }

            return(await _client.WaitResponse(message, waitForAcknowledge));
        }
        /// <summary>
        /// Pushes a message to a queue
        /// </summary>
        public async Task <HorseResult> Push(string queue, MemoryStream content, string messageId, bool waitAcknowledge,
                                             IEnumerable <KeyValuePair <string, string> > messageHeaders = null)
        {
            HorseMessage message = new HorseMessage(MessageType.QueueMessage, queue, 0);

            message.Content      = content;
            message.WaitResponse = waitAcknowledge;

            if (!string.IsNullOrEmpty(messageId))
            {
                message.SetMessageId(messageId);
            }

            if (messageHeaders != null)
            {
                foreach (KeyValuePair <string, string> pair in messageHeaders)
                {
                    message.AddHeader(pair.Key, pair.Value);
                }
            }

            if (string.IsNullOrEmpty(message.MessageId) && waitAcknowledge)
            {
                message.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            return(await _client.WaitResponse(message, waitAcknowledge));
        }
        /// <summary>
        /// Publishes a byte array data to a router
        /// </summary>
        public async Task <HorseResult> Publish(string routerName,
                                                byte[] data,
                                                string messageId        = null,
                                                bool waitForAcknowledge = false,
                                                ushort contentType      = 0,
                                                IEnumerable <KeyValuePair <string, string> > messageHeaders = null)
        {
            HorseMessage msg = new HorseMessage(MessageType.Router, routerName, contentType);

            if (!string.IsNullOrEmpty(messageId))
            {
                msg.SetMessageId(messageId);
            }
            else
            {
                msg.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            msg.WaitResponse = waitForAcknowledge;
            msg.Content      = new MemoryStream(data);

            if (messageHeaders != null)
            {
                foreach (KeyValuePair <string, string> pair in messageHeaders)
                {
                    msg.AddHeader(pair.Key, pair.Value);
                }
            }

            return(await _client.WaitResponse(msg, waitForAcknowledge));
        }
        /// <summary>
        /// Clears messages in a queue.
        /// Required administration permission.
        /// If server has no implementation for administration authorization, request is not allowed.
        /// </summary>
        public Task <HorseResult> ClearMessages(string queue, bool clearPriorityMessages, bool clearMessages)
        {
            if (!clearPriorityMessages && !clearMessages)
            {
                return(Task.FromResult(HorseResult.Failed()));
            }

            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.ClearMessages;
            message.SetTarget(queue);
            message.WaitResponse = true;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            message.AddHeader(HorseHeaders.QUEUE_NAME, queue);

            if (clearPriorityMessages)
            {
                message.AddHeader(HorseHeaders.PRIORITY_MESSAGES, "yes");
            }

            if (clearMessages)
            {
                message.AddHeader(HorseHeaders.MESSAGES, "yes");
            }

            return(_client.WaitResponse(message, true));
        }
        /// <summary>
        /// Adds new binding to a router
        /// </summary>
        /// <param name="routerName">Router name of the binding</param>
        /// <param name="type">Binding type</param>
        /// <param name="name">Binding name</param>
        /// <param name="target">Binding target. Queue name, tag name, direct receiver id, name, type, etc.</param>
        /// <param name="interaction">Binding interaction</param>
        /// <param name="bindingMethod">Binding method is used when multiple receivers available in same binding. It's used for Direct and Tag bindings.</param>
        /// <param name="contentType">Overwritten content type if specified</param>
        /// <param name="priority">Binding priority</param>
        /// <returns></returns>
        public async Task <HorseResult> AddBinding(string routerName,
                                                   BindingType type,
                                                   string name,
                                                   string target,
                                                   BindingInteraction interaction,
                                                   RouteMethod bindingMethod = RouteMethod.Distribute,
                                                   ushort?contentType        = null,
                                                   int priority = 1)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.AddBinding;
            message.SetTarget(routerName);
            message.WaitResponse = true;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            BindingInformation info = new BindingInformation
            {
                Name        = name,
                Target      = target,
                Interaction = interaction,
                ContentType = contentType,
                Priority    = priority,
                BindingType = type,
                Method      = bindingMethod
            };

            message.Serialize(info, new NewtonsoftContentSerializer());
            return(await _client.WaitResponse(message, true));
        }
Exemple #7
0
        private static async Task SendResponse(MqClient client, HorseMessage message, bool successful)
        {
            ushort       contentType = successful ? (ushort)HorseResultCode.Ok : (ushort)HorseResultCode.Failed;
            HorseMessage response    = new HorseMessage(MessageType.Response, client.UniqueId, contentType);

            response.SetMessageId(message.MessageId);
            await client.SendAsync(response);
        }
Exemple #8
0
        /// <summary>
        /// Fills binary data to the queue
        /// </summary>
        public PushResult FillData(IEnumerable <byte[]> items, bool createAsSaved, bool highPriority)
        {
            try
            {
                if (_queue.Status == QueueStatus.Stopped)
                {
                    return(PushResult.StatusNotSupported);
                }

                int max = _queue.PriorityMessagesList.Count + _queue.MessagesList.Count + items.Count();
                if (_queue.Options.MessageLimit > 0 && max > _queue.Options.MessageLimit)
                {
                    return(PushResult.LimitExceeded);
                }

                foreach (byte[] item in items)
                {
                    HorseMessage message = new HorseMessage(MessageType.QueueMessage, _queue.Name);
                    message.HighPriority = highPriority;
                    message.WaitResponse = _queue.Options.Acknowledge != QueueAckDecision.None;

                    if (_queue.Options.UseMessageId)
                    {
                        message.SetMessageId(_queue.Server.MessageIdGenerator.Create());
                    }

                    message.Content          = new MemoryStream(item);
                    message.Content.Position = 0;
                    message.CalculateLengths();

                    QueueMessage qm = new QueueMessage(message, createAsSaved);

                    if (highPriority)
                    {
                        lock (_queue.PriorityMessagesList)
                            _queue.PriorityMessagesList.AddLast(qm);
                    }
                    else
                    {
                        lock (_queue.MessagesList)
                            _queue.MessagesList.AddLast(qm);
                    }
                }

                _queue.Info.UpdateHighPriorityMessageCount(_queue.PriorityMessagesList.Count);
                _queue.Info.UpdateRegularMessageCount(_queue.MessagesList.Count);

                _ = _queue.Trigger();

                return(PushResult.Success);
            }
            catch (Exception e)
            {
                _queue.Server.SendError("FILL_DATA", e, $"QueueName:{_queue.Name}");
                return(PushResult.Error);
            }
        }
Exemple #9
0
        /// <summary>
        /// Fills JSON object data to the queue.
        /// Creates new HorseMessage and before writing content and adding into queue calls the action.
        /// </summary>
        public PushResult FillJson <T>(IEnumerable <T> items, bool createAsSaved, Action <HorseMessage, T> action) where T : class
        {
            try
            {
                if (_queue.Status == QueueStatus.Stopped)
                {
                    return(PushResult.StatusNotSupported);
                }

                int max = _queue.PriorityMessagesList.Count + _queue.MessagesList.Count + items.Count();
                if (_queue.Options.MessageLimit > 0 && max > _queue.Options.MessageLimit)
                {
                    return(PushResult.LimitExceeded);
                }

                foreach (T item in items)
                {
                    HorseMessage message = new HorseMessage(MessageType.QueueMessage, _queue.Name);
                    message.WaitResponse = _queue.Options.Acknowledge != QueueAckDecision.None;

                    if (_queue.Options.UseMessageId)
                    {
                        message.SetMessageId(_queue.Server.MessageIdGenerator.Create());
                    }

                    action(message, item);
                    message.Serialize(item, _queue.Server.MessageContentSerializer);

                    QueueMessage qm = new QueueMessage(message, createAsSaved);

                    if (message.HighPriority)
                    {
                        lock (_queue.PriorityMessagesList)
                            _queue.PriorityMessagesList.AddLast(qm);
                    }
                    else
                    {
                        lock (_queue.MessagesList)
                            _queue.MessagesList.AddLast(qm);
                    }
                }

                _queue.Info.UpdateHighPriorityMessageCount(_queue.PriorityMessagesList.Count);
                _queue.Info.UpdateRegularMessageCount(_queue.MessagesList.Count);

                _ = _queue.Trigger();

                return(PushResult.Success);
            }
            catch (Exception e)
            {
                _queue.Server.SendError("FILL_JSON", e, $"QueueName:{_queue.Name}");
                return(PushResult.Error);
            }
        }
Exemple #10
0
        /// <summary>
        /// Creates new Pull Request response message with no content
        /// </summary>
        internal static HorseMessage CreateNoContentPullResponse(HorseMessage request, string reason)
        {
            HorseMessage msg = new HorseMessage(MessageType.QueueMessage);

            msg.SetMessageId(request.MessageId);
            msg.SetTarget(request.Target);
            msg.ContentType = request.ContentType;
            msg.AddHeader(HorseHeaders.REQUEST_ID, request.MessageId);
            msg.AddHeader(HorseHeaders.NO_CONTENT, reason);
            return(msg);
        }
        /// <summary>
        /// Removes a router.
        /// Returns success result if router doesn't exists.
        /// </summary>
        public async Task <HorseResult> Remove(string name)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.RemoveRouter;
            message.SetTarget(name);
            message.WaitResponse = true;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            return(await _client.WaitResponse(message, true));
        }
        /// <summary>
        /// Creates new router.
        /// Returns success result if router already exists.
        /// </summary>
        public async Task <HorseResult> Create(string name, RouteMethod method)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.CreateRouter;
            message.SetTarget(name);
            message.WaitResponse = true;
            message.AddHeader(HorseHeaders.ROUTE_METHOD, Convert.ToInt32(method).ToString());
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            return(await _client.WaitResponse(message, true));
        }
        /// <summary>
        /// Remove a binding from a router
        /// </summary>
        public async Task <HorseResult> RemoveBinding(string routerName, string bindingName)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.RemoveBinding;
            message.SetTarget(routerName);
            message.WaitResponse = true;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            message.AddHeader(HorseHeaders.BINDING_NAME, bindingName);
            return(await _client.WaitResponse(message, true));
        }
Exemple #14
0
        /// <summary>
        /// Finds all queues in server
        /// </summary>
        public async Task <HorseModelResult <List <QueueInformation> > > List(string filter = null)
        {
            HorseMessage message = new HorseMessage();

            message.Type = MessageType.Server;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            message.ContentType = KnownContentTypes.QueueList;

            message.AddHeader(HorseHeaders.FILTER, filter);

            return(await _client.SendAndGetJson <List <QueueInformation> >(message));
        }
Exemple #15
0
        /// <summary>
        /// Request a message from Pull queue
        /// </summary>
        public async Task <PullContainer> Pull(PullRequest request, Func <int, HorseMessage, Task> actionForEachMessage = null)
        {
            HorseMessage message = new HorseMessage(MessageType.QueuePullRequest, request.Queue);

            message.SetMessageId(_client.UniqueIdGenerator.Create());
            message.AddHeader(HorseHeaders.COUNT, request.Count);

            if (request.ClearAfter == ClearDecision.AllMessages)
            {
                message.AddHeader(HorseHeaders.CLEAR, "all");
            }
            else if (request.ClearAfter == ClearDecision.PriorityMessages)
            {
                message.AddHeader(HorseHeaders.CLEAR, "High-Priority");
            }
            else if (request.ClearAfter == ClearDecision.Messages)
            {
                message.AddHeader(HorseHeaders.CLEAR, "Default-Priority");
            }

            if (request.GetQueueMessageCounts)
            {
                message.AddHeader(HorseHeaders.INFO, "yes");
            }

            if (request.Order == MessageOrder.LIFO)
            {
                message.AddHeader(HorseHeaders.ORDER, HorseHeaders.LIFO);
            }

            foreach (KeyValuePair <string, string> pair in request.RequestHeaders)
            {
                message.AddHeader(pair.Key, pair.Value);
            }

            PullContainer container = new PullContainer(message.MessageId, request.Count, actionForEachMessage);

            lock (PullContainers)
                PullContainers.Add(message.MessageId, container);

            HorseResult sent = await _client.SendAsync(message);

            if (sent.Code != HorseResultCode.Ok)
            {
                lock (PullContainers)
                    PullContainers.Remove(message.MessageId);

                container.Complete("Error");
            }

            return(await container.GetAwaitableTask());
        }
Exemple #16
0
        /// <summary>
        /// Gets all consumers of queue
        /// </summary>
        public async Task <HorseModelResult <List <ClientInformation> > > GetConsumers(string queue)
        {
            HorseMessage message = new HorseMessage();

            message.Type = MessageType.Server;
            message.SetTarget(queue);
            message.ContentType = KnownContentTypes.QueueConsumers;
            message.SetMessageId(_client.UniqueIdGenerator.Create());

            message.AddHeader(HorseHeaders.QUEUE_NAME, queue);

            return(await _client.SendAndGetJson <List <ClientInformation> >(message));
        }
Exemple #17
0
        /// <summary>
        /// Creates new response message, with no content, of the message.
        /// </summary>
        public static HorseMessage StatusResponse(HorseMessage request, ushort status)
        {
            HorseMessage response = new HorseMessage();

            response.Type = MessageType.Response;
            response.SetMessageId(request.MessageId);
            response.ContentType = status;

            response.SetTarget(request.Type == MessageType.QueueMessage
                                   ? request.Target
                                   : request.Source);

            return(response);
        }
Exemple #18
0
        /// <summary>
        /// Unsubscribes from a queue
        /// </summary>
        public async Task <HorseResult> Unsubscribe(string queue, bool verifyResponse)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.Unsubscribe;
            message.SetTarget(queue);
            message.WaitResponse = verifyResponse;

            if (verifyResponse)
            {
                message.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            return(await _client.WaitResponse(message, verifyResponse));
        }
Exemple #19
0
        /// <summary>
        /// Updates queue options
        /// </summary>
        public async Task <HorseResult> SetOptions(string queue, Action <QueueOptions> optionsAction)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.UpdateQueue;
            message.SetTarget(queue);
            message.WaitResponse = true;
            message.SetMessageId(_client.UniqueIdGenerator.Create());
            message.AddHeader(HorseHeaders.QUEUE_NAME, queue);

            QueueOptions options = new QueueOptions();

            optionsAction(options);

            message.Content = new MemoryStream();
            await JsonSerializer.SerializeAsync(message.Content, options);

            return(await _client.WaitResponse(message, true));
        }
Exemple #20
0
        /// <summary>
        /// Pushes clones of the message to cc queues
        /// </summary>
        private async Task PushOtherQueues(MqClient client, HorseMessage clone, List <string> ccList, List <KeyValuePair <string, string> > additionalHeaders)
        {
            for (int i = 0; i < ccList.Count; i++)
            {
                string cc = ccList[i];

                string[] split = cc.Split(';');
                if (split.Length < 1)
                {
                    continue;
                }

                string queueName = split[0].Trim();
                string messageId = null;
                if (split.Length > 1)
                {
                    messageId = split[1];
                }

                HorseQueue queue = await FindQueue(null, queueName, clone);

                if (queue == null)
                {
                    continue;
                }

                HorseMessage msg = clone;
                if (i < ccList.Count - 1)
                {
                    clone = clone.Clone(false, true, _server.MessageIdGenerator.Create(), additionalHeaders);
                }

                if (!string.IsNullOrEmpty(messageId))
                {
                    msg.SetMessageId(messageId);
                }

                _ = HandlePush(client, msg, queue, false);
            }
        }
Exemple #21
0
        /// <summary>
        /// Creates new queue in server
        /// </summary>
        public async Task <HorseResult> Create(string queue,
                                               Action <QueueOptions> optionsAction,
                                               string deliveryHandlerHeader = null,
                                               IEnumerable <KeyValuePair <string, string> > additionalHeaders = null)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.CreateQueue;
            message.SetTarget(queue);
            message.WaitResponse = true;
            message.AddHeader(HorseHeaders.QUEUE_NAME, queue);

            if (!string.IsNullOrEmpty(deliveryHandlerHeader))
            {
                message.AddHeader(HorseHeaders.DELIVERY_HANDLER, deliveryHandlerHeader);
            }

            if (additionalHeaders != null)
            {
                foreach (KeyValuePair <string, string> pair in additionalHeaders)
                {
                    message.AddHeader(pair.Key, pair.Value);
                }
            }

            if (optionsAction != null)
            {
                QueueOptions options = new QueueOptions();
                optionsAction(options);

                message.Content = new MemoryStream();
                await JsonSerializer.SerializeAsync(message.Content, options);
            }

            message.SetMessageId(_client.UniqueIdGenerator.Create());

            return(await _client.WaitResponse(message, true));
        }
Exemple #22
0
        /// <summary>
        /// Subscribes to a queue
        /// </summary>
        public async Task <HorseResult> Subscribe(string queue, bool verifyResponse, IEnumerable <KeyValuePair <string, string> > headers = null)
        {
            HorseMessage message = new HorseMessage();

            message.Type        = MessageType.Server;
            message.ContentType = KnownContentTypes.Subscribe;
            message.SetTarget(queue);
            message.WaitResponse = verifyResponse;

            if (headers != null)
            {
                foreach (KeyValuePair <string, string> header in headers)
                {
                    message.AddHeader(header.Key, header.Value);
                }
            }

            if (verifyResponse)
            {
                message.SetMessageId(_client.UniqueIdGenerator.Create());
            }

            return(await _client.WaitResponse(message, verifyResponse));
        }
        public async Task ReloadAfterRestart()
        {
            await Task.Delay(500);

            ConfigurationFactory.Destroy();
            RedeliveryService service = new RedeliveryService("data/reload-test.tdb.delivery");
            await service.Load();

            await service.Clear();

            await service.Set("id", 4);

            await service.Close();

            if (System.IO.File.Exists("data/config.json"))
            {
                System.IO.File.Delete("data/config.json");
            }

            if (System.IO.File.Exists("data/reload-test.tdb"))
            {
                System.IO.File.Delete("data/reload-test.tdb");
            }

            if (System.IO.File.Exists("data/reload-test.tdb.delivery"))
            {
                System.IO.File.Delete("data/reload-test.tdb.delivery");
            }

            HorseServer server = new HorseServer();
            PersistentDeliveryHandler handler = null;
            Func <DeliveryHandlerBuilder, Task <IMessageDeliveryHandler> > fac = async builder =>
            {
                DatabaseOptions options = new DatabaseOptions
                {
                    Filename             = "data/reload-test.tdb",
                    InstantFlush         = true,
                    CreateBackupOnShrink = false,
                    ShrinkInterval       = TimeSpan.FromSeconds(60)
                };

                handler = (PersistentDeliveryHandler)await builder.CreatePersistentDeliveryHandler(o =>
                {
                    return(new PersistentDeliveryHandler(builder.Queue,
                                                         options,
                                                         DeleteWhen.AfterSend,
                                                         ProducerAckDecision.None,
                                                         true));
                });

                return(handler);
            };

            HorseMq mq = server.UseHorseMq(cfg => cfg
                                           .AddPersistentQueues(q => q.KeepLastBackup())
                                           .UseDeliveryHandler(fac));

            HorseQueue queue = await mq.CreateQueue("reload-test",
                                                    o => o.Status = QueueStatus.Push);

            HorseMessage msg = new HorseMessage(MessageType.QueueMessage, "reload-test");

            msg.SetMessageId("id");
            msg.SetStringContent("Hello, World!");
            await queue.Push(msg);

            QueueMessage queueMsg = queue.Messages.FirstOrDefault();
            await handler.BeginSend(queue, queueMsg);

            await handler.RedeliveryService.Close();

            ConfigurationFactory.Destroy();

            mq = server.UseHorseMq(cfg => cfg
                                   .AddPersistentQueues(q => q.KeepLastBackup())
                                   .UseDeliveryHandler(fac));

            await mq.LoadPersistentQueues();

            HorseQueue queue2 = mq.FindQueue("reload-test");

            Assert.NotNull(queue2);
            Assert.NotEmpty(queue2.Messages);
            QueueMessage loadedMsg = queue2.Messages.FirstOrDefault();

            Assert.NotNull(loadedMsg);
            Assert.Equal(1, loadedMsg.DeliveryCount);
        }
        public async Task InPersistentHandler()
        {
            ConfigurationFactory.Destroy();
            PersistentDeliveryHandler handler = null;
            HorseServer server = new HorseServer();
            HorseMq     mq     = server.UseHorseMq(cfg => cfg
                                                   .AddPersistentQueues(q => q.KeepLastBackup())
                                                   .UseDeliveryHandler(async builder =>
            {
                DatabaseOptions options = new DatabaseOptions
                {
                    Filename             = "redelivery-test.tdb",
                    InstantFlush         = true,
                    CreateBackupOnShrink = false,
                    ShrinkInterval       = TimeSpan.FromSeconds(60)
                };

                handler = new PersistentDeliveryHandler(builder.Queue,
                                                        options,
                                                        DeleteWhen.AfterSend,
                                                        ProducerAckDecision.None,
                                                        true);
                await handler.Initialize();
                return(handler);
            }));

            HorseQueue queue = await mq.CreateQueue("test");

            HorseMessage message = new HorseMessage(MessageType.QueueMessage, "test");

            message.SetMessageId("id");
            message.SetStringContent("Hello, World!");
            QueueMessage queueMessage = new QueueMessage(message);

            await handler.BeginSend(queue, queueMessage);

            List <KeyValuePair <string, int> > deliveries = handler.RedeliveryService.GetDeliveries();

            Assert.Single(deliveries);
            Assert.Equal("id", deliveries[0].Key);
            Assert.Equal(1, deliveries[0].Value);

            string header = message.FindHeader(HorseHeaders.DELIVERY);

            Assert.Null(header);

            await handler.BeginSend(queue, queueMessage);

            deliveries = handler.RedeliveryService.GetDeliveries();
            Assert.Single(deliveries);
            Assert.Equal("id", deliveries[0].Key);
            Assert.Equal(2, deliveries[0].Value);

            header = message.FindHeader(HorseHeaders.DELIVERY);
            Assert.NotNull(header);
            Assert.Equal(2, Convert.ToInt32(header));

            queueMessage.MarkAsSent();

            await handler.EndSend(queue, queueMessage);

            deliveries = handler.RedeliveryService.GetDeliveries();
            Assert.Empty(deliveries);
        }