private void ValidateMessageHeader(IMessagingMessage message)
        {
            Logger.LogDebug("Validating message header");
            var missingFields = new List <string>();

            // the FromHerId is not checked by design. If this validation fails, we need to send a message back to the sender
            // but we have no idea who the sender is because the information is missing
            if (message.ToHerId == 0)
            {
                missingFields.Add(ServiceBusCore.ToHerIdHeaderKey);
            }
            if (string.IsNullOrEmpty(message.MessageFunction))
            {
                missingFields.Add("Label");
            }
            if (message.ApplicationTimestamp == DateTime.MinValue)
            {
                missingFields.Add(ServiceBusCore.ApplicationTimestampHeaderKey);
            }
            if (string.IsNullOrEmpty(message.ContentType))
            {
                missingFields.Add("ContentType");
            }

            if (missingFields.Count > 0)
            {
                throw new HeaderValidationException("One or more fields are missing")
                      {
                          Fields = missingFields
                      }
            }
            ;
        }
예제 #2
0
        /// <summary>
        /// Sends a prepared message
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="message">The prepared message</param>
        /// <param name="queueType">The type of queue to use</param>
        /// <param name="userId"></param>
        /// <param name="xml">Optional xml content. This will be logged depending on the logging level.</param>
        /// <returns></returns>
        private async Task Send(ILogger logger, IMessagingMessage message, QueueType queueType, string userId = "99999999999", XDocument xml = null)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            IMessagingSender messageSender = null;

            try
            {
                messageSender = SenderPool.CreateCachedMessageSender(logger, message.To);
                await messageSender.SendAsync(message).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                logger.LogException("Cannot send message to service bus. Invalid endpoint.", ex);

                throw new MessagingException(ex.Message)
                      {
                          EventId = EventIds.Send
                      };
            }
            finally
            {
                if (messageSender != null)
                {
                    SenderPool.ReleaseCachedMessageSender(logger, message.To);
                }
            }
        }
예제 #3
0
        public Task SendAsync(IMessagingMessage message)
        {
            List <IMessagingMessage> queue;

            if (_factory.Qeueues.ContainsKey(_id) == false)
            {
                queue = new List <IMessagingMessage>();
                _factory.Qeueues.Add(_id, queue);
            }
            else
            {
                queue = _factory.Qeueues[_id];
            }

            var m = message as MockMessage;

            m.Queue = queue;

            //validate To queue so we can test errors connecting to queues. Different implementations throw different exceptions
            if (!string.IsNullOrEmpty(message.To) && message.To.StartsWith("Dialog_"))
            {
                throw new MessagingException();
            }

            queue.Add(message);
            return(Task.CompletedTask);
        }
예제 #4
0
        /// <summary>
        /// Sends a prepared message
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="message">The prepared message</param>
        /// <param name="queueType">The type of queue to use</param>
        /// <param name="userId"></param>
        /// <param name="xml">Optional xml content. This will be logged depending on the logging level.</param>
        /// <returns></returns>
        private async Task Send(ILogger logger, IMessagingMessage message, QueueType queueType, string userId = "99999999999", XDocument xml = null)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            logger.LogStartSend(queueType, message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId, userId, xml);
            IMessagingSender messageSender = null;

            try
            {
                messageSender = SenderPool.CreateCachedMessageSender(logger, message.To);
                await messageSender.SendAsync(message).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                throw new MessagingException(ex.Message)
                      {
                          EventId = EventIds.Send
                      };
            }
            finally
            {
                if (messageSender != null)
                {
                    SenderPool.ReleaseCachedMessageSender(logger, message.To);
                }
            }

            logger.LogEndSend(queueType, message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId, userId);
        }
        private void ReportErrorOnRemoteCertificate(IMessagingMessage originalMessage, X509Certificate2 certificate,
                                                    CertificateErrors error)
        {
            string  errorCode;
            string  description;
            EventId id;

            switch (error)
            {
            case CertificateErrors.None:
            // no error
            case CertificateErrors.Missing:
                // if the certificate is missing, it's because we don't know where it came from
                // and have no idea where to send an error message
                return;

            case CertificateErrors.StartDate:
                errorCode   = "transport:expired-certificate";
                description = "Invalid start date";
                id          = EventIds.RemoteCertificateStartDate;
                break;

            case CertificateErrors.EndDate:
                errorCode   = "transport:expired-certificate";
                description = "Invalid end date";
                id          = EventIds.RemoteCertificateEndDate;
                break;

            case CertificateErrors.Usage:
                errorCode   = "transport:invalid-certificate";
                description = "Invalid usage";
                id          = EventIds.RemoteCertificateUsage;
                break;

            case CertificateErrors.Revoked:
                errorCode   = "transport:revoked-certificate";
                description = "Certificate has been revoked";
                id          = EventIds.RemoteCertificateRevocation;
                break;

            case CertificateErrors.RevokedUnknown:
                errorCode   = "transport:revoked-certificate";
                description = "Unable to determine revocation status";
                id          = EventIds.RemoteCertificateRevocation;
                break;

            default:     // since the value is bitcoded
                errorCode   = "transport:invalid-certificate";
                description = "More than one error with certificate";
                id          = EventIds.RemoteCertificate;
                break;
            }
            var additionalInformation =
                (error != CertificateErrors.Missing) || (error != CertificateErrors.None) ?
                new[] { certificate.Subject, certificate.Thumbprint } :
            new string[] { };

            Core.ReportErrorToExternalSender(Logger, id, originalMessage, errorCode, description, additionalInformation);
        }
        private XDocument HandlePayload(IMessagingMessage originalMessage, Stream bodyStream, string contentType, IncomingMessage incomingMessage, out bool contentWasSigned)
        {
            XDocument payload;

            if (contentType.Equals(ContentType.Text, StringComparison.OrdinalIgnoreCase) ||
                contentType.Equals(ContentType.Soap, StringComparison.OrdinalIgnoreCase))
            {
                contentWasSigned = false;
                // no certificates to validate
                payload = new NoMessageProtection().Unprotect(bodyStream, null)?.ToXDocument();
            }
            else
            {
                contentWasSigned = true;
                // if we receive enrypted messages on the error queue, we have no idea what to do with them
                // Since this can be message we sent, it's encrypted with their certificate and we don't have that private key
                if (QueueType == QueueType.Error)
                {
                    return(null);
                }

                // TODO: The whole part of validating the local certificates below should probably be move into
                // the IMessageProtection implementation, but since there are some constraints to properties on
                // IMessagingMessage we'll keep it here for now

                // in receive mode, we try to decrypt and validate content even if the certificates are invalid
                // invalid certificates are flagged to the application layer processing the decrypted message.
                // with the decrypted content, they may have a chance to figure out who sent it

                var validator = Core.CertificateValidator;
                // validate the local encryption certificate and, if present, the local legacy encryption certificate
                incomingMessage.DecryptionError = validator == null
                    ? CertificateErrors.None
                    : validator.Validate(Core.MessageProtection.EncryptionCertificate, X509KeyUsageFlags.DataEncipherment);
                // in earlier versions of Helsenorge.Messaging we removed the message, but we should rather
                // want it to be dead lettered since this is a temp issue that should be fixed locally.
                ReportErrorOnLocalCertificate(originalMessage, Core.MessageProtection.EncryptionCertificate, incomingMessage.DecryptionError, false);
                if (Core.MessageProtection.LegacyEncryptionCertificate != null)
                {
                    // this is optional information that should only be in effect durin a short transition period
                    incomingMessage.LegacyDecryptionError = validator == null
                        ? CertificateErrors.None
                        : validator.Validate(Core.MessageProtection.LegacyEncryptionCertificate, X509KeyUsageFlags.DataEncipherment);
                    // if someone forgets to remove the legacy configuration, we log an error message but don't remove it
                    ReportErrorOnLocalCertificate(originalMessage, Core.MessageProtection.LegacyEncryptionCertificate, incomingMessage.LegacyDecryptionError, false);
                }
                // validate remote signature certificate
                var signature = incomingMessage.CollaborationAgreement?.SignatureCertificate;
                incomingMessage.SignatureError = validator == null
                    ? CertificateErrors.None
                    : validator.Validate(signature, X509KeyUsageFlags.NonRepudiation);
                ReportErrorOnRemoteCertificate(originalMessage, signature, incomingMessage.SignatureError);

                // decrypt the message and validate the signatureS
                payload = Core.MessageProtection.Unprotect(bodyStream, signature)?.ToXDocument();
            }
            return(payload);
        }
예제 #7
0
        /// <summary>
        /// Removes the message from the queue as part of normal operation
        /// </summary>
        /// <param name="message"></param>
        internal static void RemoveProcessedMessageFromQueue(IMessagingMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            message.Complete();
        }
예제 #8
0
        /// <summary>
        /// Removes the message from the queue as part of normal operation
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="message"></param>
        internal static void RemoveProcessedMessageFromQueue(ILogger logger, IMessagingMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            logger.LogRemoveMessageFromQueueNormal(message.MessageId);
            message.Complete();
        }
        private void ReportErrorOnLocalCertificate(IMessagingMessage originalMessage, X509Certificate2 certificate, CertificateErrors error, bool removeMessage)
        {
            string  description;
            EventId id;

            switch (error)
            {
            case CertificateErrors.None:
                return;     // no error

            case CertificateErrors.StartDate:
                description = "Invalid start date";
                id          = EventIds.LocalCertificateStartDate;
                break;

            case CertificateErrors.EndDate:
                description = "Invalid end date";
                id          = EventIds.LocalCertificateEndDate;
                break;

            case CertificateErrors.Usage:
                description = "Invalid usage";
                id          = EventIds.LocalCertificateUsage;
                break;

            case CertificateErrors.Revoked:
                description = "Certificate has been revoked";
                id          = EventIds.LocalCertificateRevocation;
                break;

            case CertificateErrors.RevokedUnknown:
                description = "Unable to determine revocation status";
                id          = EventIds.LocalCertificateRevocation;
                break;

            case CertificateErrors.Missing:
                description = "Certificate is missing";
                id          = EventIds.LocalCertificate;
                break;

            default:     // since the value is bitcoded
                description = "More than one error with certificate";
                id          = EventIds.LocalCertificate;
                break;
            }
            Logger.LogError(id, null, "Description: {Description} Subject: {Subject} Thumbprint: {Thumbprint}",
                            description, certificate?.Subject, certificate?.Thumbprint);

            if (removeMessage)
            {
                ServiceBusCore.RemoveMessageFromQueueAfterError(Logger, originalMessage);
            }
        }
예제 #10
0
 /// <summary>
 /// Sends a message to the remote sender with information about what is wrong.
 /// Loggs information to our logs.
 /// Removes message from processing queue since there is no point in processing it again.
 /// </summary>
 /// <param name="logger"></param>
 /// <param name="id">The event id that error should be logged with</param>
 /// <param name="originalMessage"></param>
 /// <param name="errorCode"></param>
 /// <param name="description"></param>
 /// <param name="additionalData"></param>
 /// <param name="ex"></param>
 internal void ReportErrorToExternalSender(
     ILogger logger,
     EventId id,
     IMessagingMessage originalMessage,
     string errorCode,
     string description,
     IEnumerable <string> additionalData,
     Exception ex = null)
 {
     logger.LogError(id, ex, description);
     Task.WaitAll(SendError(logger, originalMessage, errorCode, description, additionalData));
     RemoveMessageFromQueueAfterError(logger, originalMessage);
 }
예제 #11
0
        private async Task <CollaborationProtocolProfile> ResolveProfile(IMessagingMessage message)
        {
            Guid id;

            if (Guid.TryParse(message.CpaId, out id) && (id != Guid.Empty))
            {
                return(await Core.CollaborationProtocolRegistry.FindAgreementByIdAsync(Logger, id).ConfigureAwait(false));
            }
            return
                // try first to find an agreement
                (await Core.CollaborationProtocolRegistry.FindAgreementForCounterpartyAsync(Logger, message.FromHerId).ConfigureAwait(false) ??
                 // if we cannot find that, we fallback to protocol (which may return a dummy protocol if things are really missing in AR)
                 await Core.CollaborationProtocolRegistry.FindProtocolForCounterpartyAsync(Logger, message.FromHerId).ConfigureAwait(false));
        }
예제 #12
0
        public async Task SendAsync(IMessagingMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var brokeredMessage = message.OriginalObject as BrokeredMessage;

            if (brokeredMessage == null)
            {
                throw new InvalidOperationException("OriginalObject is not a Brokered message");
            }

            await _implementation.SendAsync(brokeredMessage).ConfigureAwait(false);
        }
 private async Task <CollaborationProtocolProfile> ResolveProfile(IMessagingMessage message)
 {
     // if we receive an error message then CPA isn't needed because we're not decrypting the message and then the CPA info isn't needed
     if (QueueType == QueueType.Error)
     {
         return(null);
     }
     if (Guid.TryParse(message.CpaId, out Guid id) && (id != Guid.Empty))
     {
         return(await Core.CollaborationProtocolRegistry.FindAgreementByIdAsync(Logger, id).ConfigureAwait(false));
     }
     return
         // try first to find an agreement
         (await Core.CollaborationProtocolRegistry.FindAgreementForCounterpartyAsync(Logger, message.FromHerId).ConfigureAwait(false) ??
          // if we cannot find that, we fallback to protocol (which may return a dummy protocol if things are really missing in AR)
          await Core.CollaborationProtocolRegistry.FindProtocolForCounterpartyAsync(Logger, message.FromHerId).ConfigureAwait(false));
 }
예제 #14
0
        private XDocument HandlePayload(IMessagingMessage originalMessage, Stream bodyStream, string contentType, IncomingMessage incomingMessage, out bool contentWasSigned)
        {
            XDocument payload;

            if (contentType.Equals(ContentType.Text, StringComparison.OrdinalIgnoreCase) ||
                contentType.Equals(ContentType.Soap, StringComparison.OrdinalIgnoreCase))
            {
                contentWasSigned = false;
                // no certificates to validate
                payload = new NoMessageProtection().Unprotect(bodyStream, null, null, null);
            }
            else
            {
                contentWasSigned = true;
                // if we receive enrypted messages on the error queue, we have no idea what to do with them
                // Since this can be message we sent, it's encrypted with their certificate and we don't have that private key
                if (QueueType == QueueType.Error)
                {
                    return(null);
                }

                // in receive mode, we try to decrypt and validate content even if the certificates are invalid
                // invalid certificates are flagged to the application layer processing the decrypted message.
                // with the decrypted content, they may have a chance to figure out who sent it
                var decryption       = Core.Settings.DecryptionCertificate.Certificate;
                var signature        = incomingMessage.CollaborationAgreement?.SignatureCertificate;
                var legacyDecryption = Core.Settings.LegacyDecryptionCertificate?.Certificate;

                incomingMessage.DecryptionError = Core.DefaultCertificateValidator.Validate(decryption, X509KeyUsageFlags.DataEncipherment);
                ReportErrorOnLocalCertificate(originalMessage, decryption, incomingMessage.DecryptionError, true);

                incomingMessage.SignatureError = Core.DefaultCertificateValidator.Validate(signature, X509KeyUsageFlags.NonRepudiation);
                ReportErrorOnRemoteCertificate(originalMessage, signature, incomingMessage.SignatureError);

                if (legacyDecryption != null)
                {
                    // this is optional information that should only be in effect durin a short transition period
                    incomingMessage.LegacyDecryptionError = Core.DefaultCertificateValidator.Validate(legacyDecryption, X509KeyUsageFlags.DataEncipherment);
                    // if someone forgets to remove the legacy configuration, we log an error message but don't remove it
                    ReportErrorOnLocalCertificate(originalMessage, legacyDecryption, incomingMessage.LegacyDecryptionError, false);
                }

                payload = Core.DefaultMessageProtection.Unprotect(bodyStream, decryption, signature, legacyDecryption);
            }
            return(payload);
        }
        public async Task SendAsync(IMessagingMessage message)
        {
            Debug.Assert(message is OutgoingHttpMessage);
            var httpClient = new HttpClient();
            var response   = await httpClient.PostAsync(
                new Uri(new Uri(_url), _id),
                new StringContent(
                    (message as OutgoingHttpMessage).CreateHttpBody().ToString()
                    )
                ).ConfigureAwait(false); // TODO: MUST FIX caller code!

            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                var responseContent = await response.Content.ReadAsStringAsync();

                throw new ArgumentException($"Error from AMQP/HTTP server: {responseContent}");
            }
        }
        /// <summary>
        /// Called to process message
        /// </summary>
        /// <param name="rawMessage">The message from the queue</param>
        /// <param name="message">The refined message data. All information should now be present</param>
        protected override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message)
        {
            var reply = MessagingNotification.NotifySynchronousMessageReceived(message);

            if (reply == null)
            {
                throw new InvalidOperationException($"Message handler for function {message.MessageFunction} returned null");
            }

            var outgoingMessage = new OutgoingMessage()
            {
                ToHerId         = message.FromHerId,
                Payload         = reply,
                MessageFunction = message.MessageFunction,
                MessageId       = Guid.NewGuid().ToString()
            };

            Task.WaitAll(Core.Send(Logger, outgoingMessage, QueueType.SynchronousReply, rawMessage.ReplyTo, rawMessage.CorrelationId));
        }
예제 #17
0
        public async Task SendAsync(IMessagingMessage message)
        {
            Debug.Assert(message is OutgoingHttpMessage);
            var httpClient = new HttpClient();
            var request    = new HttpRequestMessage(HttpMethod.Post, new Uri(new Uri(_url), _id));

            request.Headers.Add(HttpServiceBusReceiver.CLIENT_HEADER_NAME, HttpServiceBusReceiver.GetClientHeaderValue());
            request.Content = new StringContent(
                (message as OutgoingHttpMessage).CreateHttpBody().ToString()
                );
            var response = await httpClient.SendAsync(request).ConfigureAwait(false);

            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                var responseContent = await response.Content.ReadAsStringAsync();

                throw new ArgumentException($"Error from AMQP/HTTP server: {responseContent}");
            }
        }
예제 #18
0
        public Task SendAsync(IMessagingMessage message)
        {
            List <IMessagingMessage> queue;

            if (_factory.Qeueues.ContainsKey(_id) == false)
            {
                queue = new List <IMessagingMessage>();
                _factory.Qeueues.Add(_id, queue);
            }
            else
            {
                queue = _factory.Qeueues[_id];
            }

            var m = message as MockMessage;

            m.Queue = queue;

            queue.Add(message);
            return(Task.CompletedTask);
        }
 public void NotifyHandledException(IMessagingMessage message, Exception ex)
 {
 }
 public void NotifyErrorMessageReceived(IMessagingMessage message)
 {
 }
예제 #21
0
 /// <summary>
 /// Called to process message
 /// </summary>
 /// <param name="rawMessage">The message from the queue</param>
 /// <param name="message">The refined message data. All information should now be present</param>
 protected override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message)
 {
     Logger.LogBeforeNotificationHandler(nameof(MessagingNotification.NotifySynchronousMessageReceived), message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId);
     MessagingNotification.NotifySynchronousMessageReceived(message);
     Logger.LogAfterNotificationHandler(nameof(MessagingNotification.NotifySynchronousMessageReceived), message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId);
 }
 /// <summary>
 /// Called to process message
 /// </summary>
 /// <param name="rawMessage">The message from the queue</param>
 /// <param name="message">The refined message data. All information should now be present</param>
 protected abstract void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message);
예제 #23
0
 public static void LogRemoveMessageFromQueueNormal(this ILogger logger, IMessagingMessage message, string queueName)
 {
     RemoveMessageFromQueueNormal(logger, message.MessageId, message.FromHerId, queueName, message.CorrelationId, null);
 }
 /// <summary>
 /// Called to process message
 /// </summary>
 /// <param name="rawMessage">The message from the queue</param>
 /// <param name="message">The refined message data. All information should now be present</param>
 protected override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message)
 {
     MessagingNotification.NotifyAsynchronousMessageReceived(message);
 }
        private async Task <IncomingMessage> HandleRawMessage(IMessagingMessage message, bool alwaysRemoveMessage)
        {
            if (message == null)
            {
                return(null);
            }
            Stream bodyStream = null;

            try
            {
                var incomingMessage = new IncomingMessage()
                {
                    MessageFunction = message.MessageFunction,
                    FromHerId       = message.FromHerId,
                    ToHerId         = message.ToHerId,
                    MessageId       = message.MessageId,
                    CorrelationId   = message.CorrelationId,
                    EnqueuedTimeUtc = message.EnqueuedTimeUtc,
                    RenewLock       = message.RenewLock,
                    DeliveryCount   = message.DeliveryCount
                };
                NotifyMessageProcessingStarted(incomingMessage);
                Logger.LogStartReceive(QueueType, incomingMessage);

                // we cannot dispose of the stream before we have potentially cloned the message for error use
                bodyStream = message.GetBody();

                ValidateMessageHeader(message);
                // we need the certificates for decryption and certificate use
                incomingMessage.CollaborationAgreement = await ResolveProfile(message).ConfigureAwait(false);

                var payload = HandlePayload(message, bodyStream, message.ContentType, incomingMessage, out bool contentWasSigned);
                incomingMessage.ContentWasSigned = contentWasSigned;
                if (payload != null)
                {
                    if (Core.LogPayload)
                    {
                        Logger.LogDebug(payload.ToString());
                    }
                    incomingMessage.Payload = payload;
                }
                NotifyMessageProcessingReady(message, incomingMessage);
                ServiceBusCore.RemoveProcessedMessageFromQueue(message);
                Logger.LogRemoveMessageFromQueueNormal(message, QueueName);
                NotifyMessageProcessingCompleted(incomingMessage);
                Logger.LogEndReceive(QueueType, incomingMessage);
                return(incomingMessage);
            }
            catch (SecurityException ex)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.RemoteCertificate, message, "transport:invalid-certificate", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (HeaderValidationException ex)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.MissingField, message, "transport:invalid-field-value", ex.Message, ex.Fields);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (XmlSchemaValidationException ex) // reportable error from message handler (application)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.NotXml, message, "transport:not-well-formed-xml", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (ReceivedDataMismatchException ex) // reportable error from message handler (application)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.DataMismatch, message, "transport:invalid-field-value", ex.Message, new[] { ex.ExpectedValue, ex.ReceivedValue }, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (NotifySenderException ex) // reportable error from message handler (application)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.ApplicationReported, message, "transport:internal-error", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (SenderHerIdMismatchException ex) // reportable error from message handler (application)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.DataMismatch, message, "abuse:spoofing-attack", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (PayloadDeserializationException ex) // from parsing to XML, reportable exception
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.ApplicationReported, message, "transport:not-well-formed-xml", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (AggregateException ex) when(ex.InnerException is MessagingException && ((MessagingException)ex.InnerException).EventId.Id == EventIds.Send.Id)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.ApplicationReported, message, "transport:invalid-field-value", "Invalid value in field: 'ReplyTo'", null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (UnsupportedMessageException ex)  // reportable error from message handler (application)
            {
                Core.ReportErrorToExternalSender(Logger, EventIds.ApplicationReported, message, "transport:unsupported-message", ex.Message, null, ex);
                MessagingNotification.NotifyHandledException(message, ex);
            }
            catch (Exception ex) // unknown error
            {
                message.AddDetailsToException(ex);
                Logger.LogError(EventIds.UnknownError, null, $"Message processing failed. Keeping lock until it times out and we can try again. Message expires at UTC {message.ExpiresAtUtc}");
                Logger.LogException("Unknown error", ex);
                // if something unknown goes wrong, we want to retry the message after a delay
                // we don't call Complete() or Abandon() since that will cause the message to be availble again
                // chances are that the failure may still be around
                // the Defer() method requires us to store the sequence id, but we don't have a place to store it
                // the option then is to let the lock time-out. This will happen after a couple of minutes and the
                // message becomes available again. 10 retries = 10 timeouts before it gets added to DLQ

                if (alwaysRemoveMessage)
                {
                    ServiceBusCore.RemoveMessageFromQueueAfterError(Logger, message);
                }
                MessagingNotification.NotifyUnhandledException(message, ex);
            }
            finally
            {
                bodyStream?.Dispose();
                message.Dispose();
            }
            return(null);
        }
예제 #26
0
 void IMessagingNotification.NotifyErrorMessageReceived(IMessagingMessage message)
 {
     _logger.LogDebug("NotifyErrorMessageReceived");
     _onErrorMessageReceived?.Invoke(message);
 }
예제 #27
0
 void IMessagingNotification.NotifyUnhandledException(IMessagingMessage message, Exception ex)
 {
     _logger.LogDebug("NotifyUnhandledException");
     _onUnhandledException?.Invoke(message, ex);
 }
 /// <summary>
 /// Called to process message
 /// </summary>
 /// <param name="rawMessage">The message from the queue</param>
 /// <param name="message">The refined message data. All information should now be present</param>
 protected override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message)
 {
     Logger.LogDebug("NotifyMessageProcessingReady");
     MessagingNotification.NotifySynchronousMessageReceived(message);
 }
예제 #29
0
        /// <summary>
        /// Called to process message
        /// </summary>
        /// <param name="rawMessage">The message from the queue</param>
        /// <param name="message">The refined message data. All information should now be present</param>
        protected override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message)
        {
            if (rawMessage == null)
            {
                throw new ArgumentNullException(nameof(rawMessage));
            }
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var stringBuilder = new StringBuilder();

            stringBuilder.Append($"Label: {message.MessageFunction} ");

            // we have received a soap fault
            if (message.MessageFunction.Equals(ServiceBusCore.SoapFaultLabel, StringComparison.OrdinalIgnoreCase) &&
                (message.Payload != null))
            {
                XNamespace soapNs   = "http://www.w3.org/2003/05/soap-envelope";
                XNamespace dialogNs = "http://www.kith.no/xmlstds/digitaldialog/2013-10-08";

                if (message.Payload.Root != null)
                {
                    var bodyNode  = message.Payload.Root.Element(soapNs + "Body");
                    var faultNode = bodyNode?.Element(soapNs + "Fault");
                    if (faultNode != null)
                    {
                        var valueNode = faultNode.Descendants(soapNs + "Value").FirstOrDefault();
                        if (valueNode != null)
                        {
                            stringBuilder.Append($"FaultCode: {valueNode.Value} ");
                        }
                        var reasonNode = faultNode.Descendants(soapNs + "Text").FirstOrDefault();
                        if (reasonNode != null)
                        {
                            stringBuilder.Append($"FaultReason: \"{reasonNode.Value}\" ");
                        }
                        var messageIdNode = faultNode.Descendants(dialogNs + "messageId").FirstOrDefault();
                        if (messageIdNode != null)
                        {
                            stringBuilder.Append($"MessageId: {messageIdNode.Value} ");
                        }
                        var timestampNode = faultNode.Descendants(dialogNs + "applicationTimeStamp").FirstOrDefault();
                        if (timestampNode != null)
                        {
                            stringBuilder.Append($"ApplicationTimeStamp: {timestampNode.Value} ");
                        }
                    }
                }
            }
            else // we received a message where error codes are stored in properties
            {
                foreach (var property in rawMessage.Properties)
                {
                    stringBuilder.Append($"{property.Key}: {property.Value} ");
                }
            }

            Logger.LogExternalReportedError(stringBuilder.ToString());

            Logger.LogBeforeNotificationHandler(nameof(MessagingNotification.NotifyErrorMessageReceived), message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId);
            MessagingNotification.NotifyErrorMessageReceived(rawMessage);
            Logger.LogAfterNotificationHandler(nameof(MessagingNotification.NotifyErrorMessageReceived), message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId);
        }
예제 #30
0
        /// <summary>
        /// Sends an error message
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="originalMessage">The original message the error is in response to</param>
        /// <param name="errorCode">The error code to report</param>
        /// <param name="errorDescription">The error description to report</param>
        /// <param name="additionalData">Additional information to include</param>
        /// <returns></returns>
        private async Task SendError(ILogger logger, IMessagingMessage originalMessage, string errorCode, string errorDescription, IEnumerable <string> additionalData)        //TODO: Sjekk at SendError fungerer med Http-meldinger
        {
            if (originalMessage == null)
            {
                throw new ArgumentNullException(nameof(originalMessage));
            }
            if (string.IsNullOrEmpty(errorCode))
            {
                throw new ArgumentNullException(nameof(errorCode));
            }
            if (string.IsNullOrEmpty(errorDescription))
            {
                throw new ArgumentNullException(nameof(errorDescription));
            }

            if (originalMessage.FromHerId <= 0)
            {
                logger.LogError(EventIds.MissingField, "FromHerId is missing. No idea where to send the error");
                return;
            }

            var clonedMessage = originalMessage.Clone();

            // update some properties on the cloned message
            clonedMessage.To = await ConstructQueueName(logger, originalMessage.FromHerId, QueueType.Error);             // change target

            clonedMessage.TimeToLive = Settings.Error.TimeToLive;
            clonedMessage.FromHerId  = originalMessage.ToHerId;
            clonedMessage.ToHerId    = originalMessage.FromHerId;

            if (clonedMessage.Properties.ContainsKey(OriginalMessageIdHeaderKey) == false)
            {
                clonedMessage.Properties.Add(OriginalMessageIdHeaderKey, originalMessage.MessageId);
            }
            if (clonedMessage.Properties.ContainsKey(ReceiverTimestampHeaderKey) == false)
            {
                clonedMessage.Properties.Add(ReceiverTimestampHeaderKey, DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo));
            }
            if (clonedMessage.Properties.ContainsKey(ErrorConditionHeaderKey) == false)
            {
                clonedMessage.Properties.Add(ErrorConditionHeaderKey, errorCode);
            }
            if (clonedMessage.Properties.ContainsKey(ErrorDescriptionHeaderKey) == false)
            {
                clonedMessage.Properties.Add(ErrorDescriptionHeaderKey, errorDescription);
            }

            var additionDataValue = "None";

            if (additionalData != null)
            {
                var sb = new StringBuilder();

                foreach (var item in additionalData)
                {
                    if (string.IsNullOrEmpty(item) == false)
                    {
                        sb.Append($"{item};");
                    }
                }
                additionDataValue = sb.ToString();

                if (clonedMessage.Properties.ContainsKey(ErrorConditionDataHeaderKey) == false)
                {
                    clonedMessage.Properties.Add(ErrorConditionDataHeaderKey, additionDataValue);
                }
            }
            logger.LogError("Reporting error to sender. ErrorCode: {0} ErrorDescription: {1} AdditionalData: {2}", errorCode, errorDescription, additionDataValue);
            await Send(logger, clonedMessage, QueueType.Error).ConfigureAwait(false);
        }