/// <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)); }
/// <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); }
/// <summary> /// Called prior to message processing /// </summary> /// <param name="message">Reference to the incoming message. Some fields may not have values since they get populated later in the processing pipeline.</param> protected override void NotifyMessageProcessingStarted(IncomingMessage message) { Logger.LogBeforeNotificationHandler(nameof(MessagingNotification.NotifyErrorMessageReceivedStarting), message.MessageFunction, message.FromHerId, message.ToHerId, message.MessageId); MessagingNotification.NotifyErrorMessageReceivedStarting(message); Logger.LogAfterNotificationHandler(nameof(MessagingNotification.NotifyErrorMessageReceivedStarting), 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 override void NotifyMessageProcessingReady(IMessagingMessage rawMessage, IncomingMessage message) { Logger.LogDebug("NotifyMessageProcessingReady"); MessagingNotification.NotifySynchronousMessageReceived(message); }
/// <summary> /// Called when message processing is complete /// </summary> /// <param name="message">Reference to the incoming message</param> protected override void NotifyMessageProcessingCompleted(IncomingMessage message) { MessagingNotification.NotifySynchronousMessageReceivedCompleted(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); }
/// <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); }
/// <summary> /// Called prior to message processing /// </summary> /// <param name="message">Reference to the incoming message. Some fields may not have values since they get populated later in the processing pipeline.</param> protected override void NotifyMessageProcessingStarted(IncomingMessage message) { MessagingNotification.NotifyAsynchronousMessageReceivedStarting(message); }
/// <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); }