public void Serialize_Deserialize_TransportMessage() { var types = new List<Type> { typeof(C1), typeof(C2) }; var mapper = new MessageMapper(); mapper.Initialize(types); var serializer = new XmlMessageSerializer(mapper); serializer.Initialize(types); var transportMessage = new TransportMessage(); transportMessage.Id = Guid.NewGuid().ToString(); transportMessage.IdForCorrelation = Guid.NewGuid().ToString(); transportMessage.ReturnAddress = Guid.NewGuid().ToString(); transportMessage.WindowsIdentityName = string.Empty; transportMessage.TimeSent = DateTime.Now; transportMessage.Headers = new List<HeaderInfo>(); transportMessage.Body = new object[] { new C1() { Data = "o'tool" }, new C2() { Data = "Timmy" } }; var newTransportMessage = Execute(transportMessage, serializer); var messages = newTransportMessage.Body; Assert.AreEqual(2, messages.Count()); Assert.AreEqual(1, messages.Count(x => x is C1)); Assert.AreEqual(1, messages.Count(x => x is C2)); Assert.AreEqual("o'tool", ((C1)messages.First(x => x is C1)).Data); Assert.AreEqual("Timmy", ((C2)messages.First(x => x is C2)).Data); Assert.AreEqual(transportMessage.Id, newTransportMessage.Id); Assert.AreEqual(transportMessage.IdForCorrelation, newTransportMessage.IdForCorrelation); Assert.AreEqual(transportMessage.ReturnAddress, newTransportMessage.ReturnAddress); Assert.AreEqual(transportMessage.TimeSent, newTransportMessage.TimeSent); Assert.AreEqual(transportMessage.Headers, newTransportMessage.Headers); Assert.AreNotSame(transportMessage, newTransportMessage); }
public void Serialize(TransportMessage transportMessage, Stream outputStream) { var xs = GetXmlSerializer(); var doc = new XmlDocument(); using (var tempstream = new MemoryStream()) { xs.Serialize(tempstream, transportMessage); tempstream.Position = 0; doc.Load(tempstream); } if (transportMessage.Body != null && transportMessage.BodyStream == null) { transportMessage.BodyStream = new MemoryStream(); this.messageSerializer.Serialize(transportMessage.Body, transportMessage.BodyStream); } // Reset the stream, so that we can read it back out as data transportMessage.BodyStream.Position = 0; var data = new StreamReader(transportMessage.BodyStream).ReadToEnd(); var bodyElement = doc.CreateElement("Body"); bodyElement.AppendChild(doc.CreateCDataSection(data)); doc.DocumentElement.AppendChild(bodyElement); doc.Save(outputStream); outputStream.Position = 0; }
public void OnMessageHandled(ITransport transport, TransportMessage transportMessage, double elapsedMilliseconds) { var tr = (long)Math.Round(elapsedMilliseconds); Metrics.Default.SendBatch() .AddTiming("CWServiceBus.MessageHandled.Destination." + transport.ListenerQueue, tr) .AddTiming("CWServiceBus.MessageHandled.Message." + transportMessage.Body[0].GetType().Name, tr) .Send(); }
public static TransportMessage Execute(TransportMessage transportMessage, IMessageSerializer messageSerializer) { var serializer = new XmlTransportMessageSerializer(messageSerializer); using (var stream = new MemoryStream()) { serializer.Serialize(transportMessage, stream); Debug.WriteLine(Encoding.ASCII.GetString(stream.ToArray())); stream.Position = 0; return serializer.Deserialize(stream, true); } }
private bool HandledMaxRetries(TransportMessage message, out Exception lastException) { string messageId = message.Id; failuresPerMessageLocker.EnterReadLock(); if (failuresPerMessage.ContainsKey(messageId) && (failuresPerMessage[messageId] >= maxRetries)) { failuresPerMessageLocker.ExitReadLock(); failuresPerMessageLocker.EnterWriteLock(); lastException = exceptionsForMessages[messageId]; failuresPerMessage.Remove(messageId); exceptionsForMessages.Remove(messageId); failuresPerMessageLocker.ExitWriteLock(); return true; } lastException = null; failuresPerMessageLocker.ExitReadLock(); return false; }
/// <summary> /// This is a special helper method which will cause the transport to receive messages as if they came off the bus /// </summary> public void ReceiveMessages(object[] messages, IEnumerable<HeaderInfo> headers) { needToAbort = false; messageId = string.Empty; try { TransactionWrapper.RunInTransaction(transaction => { var transportMessage = new TransportMessage() { Id = Guid.NewGuid().ToString(), IdForCorrelation = Guid.NewGuid().ToString(), Body = messages, TimeSent = DateTime.UtcNow, MessageIntent = MessageIntentEnum.Send, Headers = headers.ToList(), }; //care about failures here var exceptionFromMessageHandling = OnTransportMessageReceived(transportMessage); //and here var exceptionFromMessageModules = OnFinishedMessageProcessing(); //but need to abort takes precedence - failures aren't counted here, //so messages aren't moved to the error queue. if (needToAbort) throw new AbortHandlingCurrentMessageException(); if (exceptionFromMessageHandling != null) //cause rollback throw exceptionFromMessageHandling; if (exceptionFromMessageModules != null) //cause rollback throw exceptionFromMessageModules; }); } catch (AbortHandlingCurrentMessageException) { //in case AbortHandlingCurrentMessage was called //don't increment failures, we want this message kept around. return; } catch (Exception e) { var originalException = e; if (originalException is TransportMessageHandlingFailedException) originalException = ((TransportMessageHandlingFailedException)e).OriginalException; OnFailedMessageProcessing(originalException); throw; } }
private void ProcessMessage(TransportMessage transportMessage) { messageId = transportMessage.Id; var exceptionFromStartedMessageHandling = OnStartedMessageProcessing(transportMessage); Exception lastException = null; if (HandledMaxRetries(transportMessage, out lastException)) { try { this.WriteFailedMessage(transportMessage, lastException, transportMessage.BodyString, transportMessage.HeadersString); if (MessageFault != null) MessageFault(this, new TransportMessageFaultEventArgs(transportMessage, lastException, "ProcessingFailed")); SendFailureMessage(transportMessage, lastException, "ProcessingFailed"); } catch (Exception e) { Logger.FatalFormat("Fault manager failed to process the failed message {0}", e, transportMessage); // TODO critical error will stop the transport from handling new messages //Configure.Instance.OnCriticalError(); } Logger.Error(string.Format("Message has failed the maximum number of times allowed, ID={0}.", transportMessage.Id)); OnFinishedMessageProcessing(); return; } if (exceptionFromStartedMessageHandling != null) throw exceptionFromStartedMessageHandling; //cause rollback //care about failures here var exceptionFromMessageHandling = OnTransportMessageReceived(transportMessage); //and here var exceptionFromMessageModules = OnFinishedMessageProcessing(); //but need to abort takes precedence - failures aren't counted here, //so messages aren't moved to the error queue. if (needToAbort) throw new AbortHandlingCurrentMessageException(); if (exceptionFromMessageHandling != null) //cause rollback throw exceptionFromMessageHandling; if (exceptionFromMessageModules != null) //cause rollback throw exceptionFromMessageModules; }
private void OnSerializationFailed(Guid messageId, TransportMessage transportMessage, string body, string headers, Exception exception) { try { this.WriteFailedMessage(transportMessage, exception, body, headers); if (MessageFault != null) MessageFault(this, new TransportMessageFaultEventArgs(transportMessage, exception, "SerializationFailed")); SendFailureMessage(transportMessage, exception, "SerializationFailed"); } catch (Exception e) { Logger.FatalFormat("Fault manager failed to process the failed message {0}", e); // TODO critical error will stop the transport from handling new messages //Configure.Instance.OnCriticalError(); } }
public void ReceiveMessage(SqlTransaction transaction) { TransportMessage message = null; Guid id; try { using (var cmd = transaction.Connection.CreateCommand()) { cmd.Transaction = transaction; cmd.CommandText = string.Format(SqlCommands.SelectMessage, ListenerQueue); var backoff = new BackOff(1000); while (message == null) { using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { message = new TransportMessage(); id = reader.GetGuid(0); message.Id = id.ToString(); message.CorrelationId = reader.GetString(1) ?? string.Empty; message.ReturnAddress = reader.GetString(2); message.MessageIntent = (MessageIntentEnum)reader.GetByte(3); message.HeadersString = reader.GetString(4) ?? string.Empty; message.BodyString = reader.GetString(5) ?? string.Empty; try { using (var bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(message.BodyString))) { message.Body = MessageSerializer.Deserialize(bodyStream); } if (message.HeadersString.Length > 0) { using (var headersStream = new MemoryStream(Encoding.UTF8.GetBytes(message.HeadersString))) { message.Headers = MessageSerializer.Deserialize(headersStream).Cast<HeaderInfo>().ToList(); } } } catch (Exception ex) { Logger.Error("Could not extract message data.", ex); OnSerializationFailed(id, message, message.BodyString, message.HeadersString, ex); return; // deserialization failed - no reason to try again, so don't throw } } } if (message == null) { backoff.Wait(() => true); } } } } catch (Exception e) { Logger.Error("Error in receiving message from queue.", e); throw; // Throw to rollback } finally { transactionWaitPool.Release(1); releasedWaitLock = true; } // No message? That's okay if (message == null) { return; } // Set the correlation Id if (string.IsNullOrEmpty(message.IdForCorrelation)) { message.IdForCorrelation = message.Id; } ProcessMessage(message); }
private void WriteFailedMessage(Guid messageId, Message serviceBrokerMessage, TransportMessage transportMessage, Exception exception, int status) { try { // Write a failed message TransactionWrapper.RunInTransaction(transaction => { using (var command = transaction.Connection.CreateCommand()) { command.CommandText = "cw_InsertFailedMessage"; command.CommandType = CommandType.StoredProcedure; if (transportMessage != null) command.Parameters.AddWithValue("@originService", transportMessage.ReturnAddress); else command.Parameters.AddWithValue("@originService", string.Empty); command.Parameters.AddWithValue("@queueName", this.ListenerQueue); command.Parameters.AddWithValue("@queueService", this.ReturnAddress); command.Parameters.AddWithValue("@messageId", messageId); command.Parameters.AddWithValue("@messageStatus", (int)status); command.Parameters.AddWithValue("@messageData", serviceBrokerMessage.Body); if (exception != null) command.Parameters.AddWithValue("@errorMessage", FormatErrorMessage(exception)); else command.Parameters.AddWithValue("@errorMessage", DBNull.Value); command.Transaction = transaction; command.ExecuteNonQuery(); } }); } catch (Exception e) { Logger.Fatal("Failed to write ServiceBroker Error Message", e); // suppress -- don't let this exception take down the process } }
private void SendFailureMessage(TransportMessage message, Exception e, string reason) { if (message == null) return; message.MessageIntent = MessageIntentEnum.FaultNotification; SetExceptionHeaders(message, e, reason); try { Send(message, this.faultForwardDestinations); } catch (Exception exception) { var errorMessage = string.Format("Could not forward failed message to error queue, reason: {0}.", exception.ToString()); Logger.Fatal(errorMessage, exception); throw new InvalidOperationException(errorMessage, exception); } }
public void Send(TransportMessage toSend, IEnumerable<string> destinations) { var destinationQueue = string.Empty; try { TransactionWrapper.RunInTransaction(transaction => { var id = Guid.NewGuid(); toSend.Id = id.ToString(); toSend.TimeSent = DateTime.UtcNow; toSend.ReturnAddress = this.ListenerQueue; var serializedMessage = string.Empty; var messages = ""; var headers = ""; using (var stream = new MemoryStream()) { MessageSerializer.Serialize(toSend.Body, stream); messages = Encoding.UTF8.GetString(stream.ToArray()); } if (toSend.Headers != null && toSend.Headers.Count > 0) { using (var stream = new MemoryStream()) { MessageSerializer.Serialize(toSend.Headers.ToArray(), stream); headers = Encoding.UTF8.GetString(stream.ToArray()); } } using (var cmd = transaction.Connection.CreateCommand()) { cmd.Transaction = transaction; cmd.Parameters.AddWithValue("@Id", id); var paramCorrelationId = cmd.Parameters.AddWithValue("@CorrelationId", toSend.CorrelationId ?? string.Empty); paramCorrelationId.SqlDbType = SqlDbType.VarChar; paramCorrelationId.Size = 255; var paramReplyToAddress = cmd.Parameters.AddWithValue("@ReplyToAddress", this.ListenerQueue); paramReplyToAddress.SqlDbType = SqlDbType.VarChar; paramReplyToAddress.Size = 255; cmd.Parameters.AddWithValue("@MessageIntent", (byte)toSend.MessageIntent); var paramHeaders = cmd.Parameters.AddWithValue("@Headers", headers); paramHeaders.Size = -1; var paramBody = cmd.Parameters.AddWithValue("@Body", messages); paramBody.Size = -1; foreach (var destination in destinations) { destinationQueue = destination; cmd.CommandText = string.Format(SqlCommands.InsertMessage, destination); cmd.ExecuteNonQuery(); if (Logger.IsDebugEnabled) Logger.Debug(string.Format("Sending message {0} with ID {1} to destination {2}.\n" + "ToString() of the message yields: {3}\n" + "Message headers:\n{4}", toSend.Body[0].GetType().AssemblyQualifiedName, toSend.Id, destination, toSend.Body[0], string.Join(", ", toSend.Headers.Select(h => h.Key + ":" + h.Value).ToArray()) )); } } }); } catch (SqlException ex) { if (ex.Number == 208) { var msg = string.Format("Failed to send message to address: [{0}]", destinationQueue); throw new QueueNotFoundException(toSend, msg, ex); } } }
private Exception OnStartedMessageProcessing(TransportMessage msg) { try { if (StartedMessageProcessing != null) StartedMessageProcessing(this, new StartedMessageProcessingEventArgs(msg)); } catch (Exception e) { Logger.Error("Failed raising 'started message processing' event.", e); return e; } return null; }
public MessageContext(TransportMessage transportMessage) { this.transportMessage = transportMessage; }
public TransportMessageReceivedEventArgs(TransportMessage m) { message = m; }
public QueueNotFoundException(TransportMessage transportMessage, string message, SqlException innerException) : base(message, innerException) { this.TransportMessage = transportMessage; }
public TransportMessageFaultEventArgs(TransportMessage m, Exception e, string reason) { Message = m; Exception = e; Reason = reason; }
private Exception OnTransportMessageReceived(TransportMessage msg) { try { if (TransportMessageReceived != null) TransportMessageReceived(this, new TransportMessageReceivedEventArgs(msg)); } catch (Exception e) { var originalException = e; if (e is TransportMessageHandlingFailedException) originalException = ((TransportMessageHandlingFailedException)e).OriginalException; Logger.Warn("Failed raising 'transport message received' event for message with ID=" + msg.Id, originalException); return e; } return null; }
public StartedMessageProcessingEventArgs(TransportMessage m) { message = m; }
private void WriteFailedMessage(TransportMessage transportMessage, Exception exception, string originalBody, string originalHeaders) { try { // Write a failed message TransactionWrapper.RunInTransaction(transaction => { using (var command = transaction.Connection.CreateCommand()) { command.CommandText = SqlCommands.InsertPoisonMessage; var paramQueue = command.Parameters.AddWithValue("@Queue", this.ListenerQueue); paramQueue.Size = 255; command.Parameters.AddWithValue("@InsertDateTime", DateTime.UtcNow); command.Parameters.AddWithValue("@Id", Guid.Parse(transportMessage.Id)); var paramCorrelationId = command.Parameters.AddWithValue("@CorrelationId", transportMessage.CorrelationId ?? string.Empty); paramCorrelationId.SqlDbType = SqlDbType.VarChar; paramCorrelationId.Size = 255; var paramReplyToAddress = command.Parameters.AddWithValue("@ReplyToAddress", transportMessage.ReturnAddress); paramReplyToAddress.SqlDbType = SqlDbType.VarChar; paramReplyToAddress.Size = 255; command.Parameters.AddWithValue("@MessageIntent", (byte)transportMessage.MessageIntent); var paramHeaders = command.Parameters.AddWithValue("@Headers", originalHeaders ?? string.Empty); paramHeaders.Size = -1; var paramBody = command.Parameters.AddWithValue("@Body", originalBody ?? string.Empty); paramBody.Size = -1; if (exception != null) { var paramException = command.Parameters.AddWithValue("@Exception", FormatErrorMessage(exception)); paramException.Size = -1; } else { command.Parameters.AddWithValue("@Exception", DBNull.Value); } command.Transaction = transaction; command.ExecuteNonQuery(); } }); } catch (Exception e) { Logger.Fatal("Failed to write ServiceBroker Error Message", e); // suppress -- don't let this exception take down the process } }
private TransportMessage MakeTransportMessage(params IMessage[] input) { var transportMessage = new TransportMessage(); transportMessage.Id = Guid.NewGuid().ToString(); transportMessage.IdForCorrelation = Guid.NewGuid().ToString(); transportMessage.ReturnAddress = Guid.NewGuid().ToString(); transportMessage.WindowsIdentityName = string.Empty; transportMessage.TimeSent = DateTime.Now; transportMessage.Headers = new List<HeaderInfo>(); transportMessage.Body = input; return transportMessage; }
private void SetExceptionHeaders(TransportMessage message, Exception e, string reason) { if (message.Headers == null) message.Headers = new List<HeaderInfo>(); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.Reason", Value = reason }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.ExceptionType", Value = e.GetType().FullName }); if (e.InnerException != null) message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.InnerExceptionType", Value = e.InnerException.GetType().FullName }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.HelpLink", Value = e.HelpLink }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.Message", Value = e.Message }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.Source", Value = e.Source }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.ExceptionInfo.StackTrace", Value = e.StackTrace }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.OriginalId", Value = message.Id }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.FaultedAddress", Value = this.ListenerQueue }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.SqlServer.FaultedQueue", Value = this.ListenerQueue }); message.Headers.Add(new HeaderInfo() { Key = "CWServiceBus.TimeOfFailure", Value = DateTime.UtcNow.ToString("o") }); }
public void Send(TransportMessage toSend, IEnumerable<string> destinations) { TransactionWrapper.RunInTransaction(transaction => { toSend.TimeSent = DateTime.UtcNow; toSend.ReturnAddress = this.ReturnAddress; var serializedMessage = string.Empty; using (var stream = new MemoryStream()) { TransportMessageSerializer.Serialize(toSend, stream); foreach (var destination in destinations) { var conversationHandle = ServiceBrokerWrapper.SendOne(transaction, ReturnAddress, destination, NServiceBusTransportMessageContract, NServiceBusTransportMessage, stream.ToArray()); toSend.Id = conversationHandle.ToString(); if (Logger.IsDebugEnabled) Logger.Debug(string.Format("Sending message {0} with ID {1} to destination {2}.\n" + "ToString() of the message yields: {3}\n" + "Message headers:\n{4}", toSend.Body[0].GetType().AssemblyQualifiedName, toSend.Id, destination, toSend.Body[0], string.Join(", ", toSend.Headers.Select(h => h.Key + ":" + h.Value).ToArray()) )); } } }); }