void CreateQueueIfNecessary(string address, string identity)
        {
            var msmqAddress = MsmqAddress.Parse(address);

            Logger.Debug($"Creating '{address}' if needed.");

            if (msmqAddress.IsRemote)
            {
                Logger.Info($"'{address}' is a remote queue and won't be created");
                return;
            }

            var queuePath = msmqAddress.PathWithoutPrefix;

            if (MessageQueue.Exists(queuePath))
            {
                Logger.Debug($"'{address}' already exists");
                return;
            }

            try
            {
                using (var queue = MessageQueue.Create(queuePath, useTransactionalQueues))
                {
                    Logger.Debug($"Created queue, path: [{queuePath}], identity: [{identity}], transactional: [{useTransactionalQueues}]");

                    try
                    {
                        queue.SetPermissions(identity, MessageQueueAccessRights.WriteMessage);
                        queue.SetPermissions(identity, MessageQueueAccessRights.ReceiveMessage);
                        queue.SetPermissions(identity, MessageQueueAccessRights.PeekMessage);

                        queue.SetPermissions(LocalAdministratorsGroupName, MessageQueueAccessRights.FullControl);
                    }
                    catch (MessageQueueException permissionException) when(permissionException.MessageQueueErrorCode == MessageQueueErrorCode.FormatNameBufferTooSmall)
                    {
                        Logger.Warn($"The name for queue '{queue.FormatName}' is too long for permissions to be applied. Please consider a shorter endpoint name.", permissionException);
                    }
                }
            }
            catch (MessageQueueException ex) when(ex.MessageQueueErrorCode == MessageQueueErrorCode.QueueExists)
            {
                //Solves the race condition problem when multiple endpoints try to create same queue (e.g. error queue).
            }
        }
Example #2
0
 public override string MakeCanonicalForm(string transportAddress)
 {
     return(MsmqAddress.Parse(transportAddress).ToString());
 }
Example #3
0
        void SendToDelayedDeliveryQueue(TransportTransaction transaction, UnicastTransportOperation transportOperation)
        {
            onSendCallback?.Invoke(transaction, transportOperation);
            var message = transportOperation.Message;

            transportOperation.Properties[TimeoutDestination] = transportOperation.Destination;
            DateTimeOffset deliverAt;

            if (transportOperation.Properties.DelayDeliveryWith != null)
            {
                deliverAt = DateTimeOffset.UtcNow + transportOperation.Properties.DelayDeliveryWith.Delay;
            }
            else // transportOperation.Properties.DoNotDeliverBefore != null
            {
                deliverAt = transportOperation.Properties.DoNotDeliverBefore.At;
            }

            transportOperation.Properties[TimeoutDestination] = transportOperation.Destination;
            transportOperation.Properties[TimeoutAt]          = DateTimeOffsetHelper.ToWireFormattedString(deliverAt);

            var destinationAddress = MsmqAddress.Parse(timeoutsQueue);

            foreach (var kvp in transportOperation.Properties)
            {
                //Use add to force exception if user adds a custom header that has the same name as the prefix + property name
                transportOperation.Message.Headers.Add($"{MsmqUtilities.PropertyHeaderPrefix}{kvp.Key}", kvp.Value);
            }

            try
            {
                using (var q = new MessageQueue(destinationAddress.FullPath, false, transportSettings.UseConnectionCache, QueueAccessMode.Send))
                {
                    using (var toSend = MsmqUtilities.Convert(message))
                    {
                        toSend.UseDeadLetterQueue = true; //Always used DLQ for delayed messages
                        toSend.UseJournalQueue    = transportSettings.UseJournalQueue;

                        if (transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated)
                        {
                            q.Send(toSend, string.Empty, GetIsolatedTransactionType());
                            return;
                        }

                        if (TryGetNativeTransaction(transaction, out var activeTransaction))
                        {
                            q.Send(toSend, string.Empty, activeTransaction);
                            return;
                        }

                        q.Send(toSend, string.Empty, GetTransactionTypeForSend());
                    }
                }
            }
            catch (MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.QueueNotFound)
                {
                    throw new QueueNotFoundException(timeoutsQueue, $"Failed to send the message to the local delayed delivery queue [{timeoutsQueue}]: queue does not exist.", ex);
                }

                ThrowFailedToSendException(timeoutsQueue, ex);
            }
            catch (Exception ex)
            {
                ThrowFailedToSendException(timeoutsQueue, ex);
            }
        }
Example #4
0
        void SendToDestination(TransportTransaction transaction, UnicastTransportOperation transportOperation)
        {
            onSendCallback?.Invoke(transaction, transportOperation);
            var message            = transportOperation.Message;
            var destinationAddress = MsmqAddress.Parse(transportOperation.Destination);

            var dispatchProperties = transportOperation.Properties;

            if (IsCombiningTimeToBeReceivedWithTransactions(
                    transaction,
                    transportOperation.RequiredDispatchConsistency,
                    dispatchProperties))
            {
                if (transportSettings.UseNonNativeTimeToBeReceivedInTransactions)
                {
                    dispatchProperties.DiscardIfNotReceivedBefore =
                        new DiscardIfNotReceivedBefore(Message.InfiniteTimeout);
                }
                else
                {
                    throw new Exception(
                              $"Failed to send message to address: {destinationAddress.Queue}@{destinationAddress.Machine}. Sending messages with a custom TimeToBeReceived is not supported on transactional MSMQ.");
                }
            }

            try
            {
                using (var q = new MessageQueue(destinationAddress.FullPath, false, transportSettings.UseConnectionCache, QueueAccessMode.Send))
                {
                    using (var toSend = MsmqUtilities.Convert(message))
                    {
                        if (dispatchProperties.DiscardIfNotReceivedBefore?.MaxTime < MessageQueue.InfiniteTimeout)
                        {
                            toSend.TimeToBeReceived = dispatchProperties.DiscardIfNotReceivedBefore.MaxTime;
                        }

                        var useDeadLetterQueue = dispatchProperties.ShouldUseDeadLetterQueue();
                        if (useDeadLetterQueue.HasValue)
                        {
                            toSend.UseDeadLetterQueue = useDeadLetterQueue.Value;
                        }
                        else
                        {
                            var ttbrRequested = toSend.TimeToBeReceived < MessageQueue.InfiniteTimeout;
                            toSend.UseDeadLetterQueue = ttbrRequested
                                ? transportSettings.UseDeadLetterQueueForMessagesWithTimeToBeReceived
                                : transportSettings.UseDeadLetterQueue;
                        }

                        toSend.UseJournalQueue = dispatchProperties.ShouldUseJournalQueue() ??
                                                 transportSettings.UseJournalQueue;

                        toSend.TimeToReachQueue = transportSettings.TimeToReachQueue;

                        if (message.Headers.TryGetValue(Headers.ReplyToAddress, out var replyToAddress))
                        {
                            toSend.ResponseQueue = new MessageQueue(MsmqAddress.Parse(replyToAddress).FullPath);
                        }

                        var label = GetLabel(message);

                        if (transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated)
                        {
                            q.Send(toSend, label, GetIsolatedTransactionType());
                            return;
                        }

                        if (TryGetNativeTransaction(transaction, out var activeTransaction))
                        {
                            q.Send(toSend, label, activeTransaction);
                            return;
                        }

                        q.Send(toSend, label, GetTransactionTypeForSend());
                    }
                }
            }
            catch (MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.QueueNotFound)
                {
                    var msg = transportOperation.Destination == null
                        ? "Failed to send message. Target address is null."
                        : $"Failed to send message to address: [{transportOperation.Destination}]";

                    throw new QueueNotFoundException(transportOperation.Destination, msg, ex);
                }

                ThrowFailedToSendException(transportOperation.Destination, ex);
            }
            catch (Exception ex)
            {
                ThrowFailedToSendException(transportOperation.Destination, ex);
            }
        }
Example #5
0
        void ExecuteTransportOperation(TransportTransaction transaction, UnicastTransportOperation transportOperation)
        {
            var message = transportOperation.Message;

            var destination        = transportOperation.Destination;
            var destinationAddress = MsmqAddress.Parse(destination);

            if (IsCombiningTimeToBeReceivedWithTransactions(
                    transaction,
                    transportOperation.RequiredDispatchConsistency,
                    transportOperation.DeliveryConstraints))
            {
                throw new Exception($"Failed to send message to address: {destinationAddress.Queue}@{destinationAddress.Machine}. Sending messages with a custom TimeToBeReceived is not supported on transactional MSMQ.");
            }

            try
            {
                using (var q = new MessageQueue(destinationAddress.FullPath, false, settings.UseConnectionCache, QueueAccessMode.Send))
                {
                    using (var toSend = MsmqUtilities.Convert(message, transportOperation.DeliveryConstraints))
                    {
                        var ttbrRequested = toSend.TimeToBeReceived < MessageQueue.InfiniteTimeout;

                        toSend.UseDeadLetterQueue = ttbrRequested ? settings.UseDeadLetterQueueForMessagesWithTimeToBeReceived : settings.UseDeadLetterQueue;
                        toSend.UseJournalQueue    = settings.UseJournalQueue;
                        toSend.TimeToReachQueue   = settings.TimeToReachQueue;

                        if (message.Headers.TryGetValue(Headers.ReplyToAddress, out var replyToAddress))
                        {
                            toSend.ResponseQueue = new MessageQueue(MsmqAddress.Parse(replyToAddress).FullPath);
                        }

                        var label = GetLabel(message);

                        if (transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated)
                        {
                            q.Send(toSend, label, GetIsolatedTransactionType());
                            return;
                        }

                        if (TryGetNativeTransaction(transaction, out var activeTransaction))
                        {
                            q.Send(toSend, label, activeTransaction);
                            return;
                        }

                        q.Send(toSend, label, GetTransactionTypeForSend());
                    }
                }
            }
            catch (MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.QueueNotFound)
                {
                    var msg = destination == null
                        ? "Failed to send message. Target address is null."
                        : $"Failed to send message to address: [{destination}]";

                    throw new QueueNotFoundException(destination, msg, ex);
                }

                ThrowFailedToSendException(destination, ex);
            }
            catch (Exception ex)
            {
                ThrowFailedToSendException(destination, ex);
            }
        }