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). } }
public override string MakeCanonicalForm(string transportAddress) { return(MsmqAddress.Parse(transportAddress).ToString()); }
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); } }
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); } }
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); } }