public void SerializeMessage(IMessageEnvelope<object> message, IModel model, out IBasicProperties headers, out byte[] body, out string routingKey) { Stream stream = Serializer.Serialize(message); var messageBuilder = new MapMessageBuilder(model); messageBuilder.Headers[MessageTypeHeader] = message.GetType().GetGenericArguments()[0].AssemblyQualifiedName; headers = (IBasicProperties)messageBuilder.GetContentHeader(); routingKey = message.Message.GetType().ToRoutingKey(); body = new byte[stream.Length]; stream.Read(body, 0, body.Length); }
/// <summary> /// Default SendMessage should provide performance statistics. Default SendMessage should be <generic/> and be reused. /// </summary> /// <param name="sourceAddress"></param> /// <param name="destAddress"></param> /// <param name="op"></param> /// <param name="parameters"></param> /// <param name="correlationID"></param> /// <param name="retVal"></param> /// <returns></returns> public bool SendMessageImpl( RequestData req ) { try { MapMessageBuilder builder = new MapMessageBuilder ( this.OutboundChannel ); #region copy dictionary to headers //there is no other way than if (req.Data != null) foreach (DictionaryEntry entry in req.Data) { builder.Headers.Add ( (string)entry.Key, entry.Value ); } //map response if (req.Response != null) { var parameters = req.Response.Serialize (); if (parameters != null) foreach (DictionaryEntry entry in parameters) { builder.Headers.Add ( (string)entry.Key, entry.Value ); } } #endregion //write body if(req.Body != null) builder.RawWrite(Encoding.UTF8.GetBytes(req.Body)); //who is publishing - it can be used to determine return route builder.Properties.AppId = req.SourceAddress; //each message has id for traceability builder.Properties.MessageId = Guid.NewGuid ().ToString (); //this cid will be used for response if (!string.IsNullOrEmpty ( req.CorrelationId)) builder.Properties.CorrelationId = req.CorrelationId; //what message we want to send builder.Headers["op"] = req.Op; //time of sending builder.Headers["sent"] = DateTime.Now.ToString ( "o" ); //timeout; will help second party to cancel reposnse thus limitting traffic builder.Headers["timeout"] = 0; bool confirmed; //have to block because it is concurent access to this resource lock (this.OutboundChannel) { //publish to topic exchange where routin key=destination process address, mandatory=true this.OutboundChannel.BasicPublish ( this.Exchange, req.DestAddress, true, builder.Properties, RMQBus.GetBodyBytes(req.Body) ); //sometimes it blocks, maybe I should use timeout and resend? if the second party gets message second time then it should send back the same response confirmed = this.OutboundChannel.WaitForConfirms (); } if (confirmed) Tracer.TraceEvent ( System.Diagnostics.TraceEventType.Verbose, 0, "[{0}] op '{1}' dest. {2} value {3} cid {4}", this, req.Op, req.DestAddress, req.Response, req.CorrelationId ); else Tracer.TraceEvent ( System.Diagnostics.TraceEventType.Error, 0, "[{0}] not confirmed op '{1}' dest. {2} value {3} cid {4}", this, req.Op, req.DestAddress, req.Response, req.CorrelationId ); return confirmed; } catch (Exception ex) { Tracer.TraceEvent ( System.Diagnostics.TraceEventType.Error, 0, "{0} send message exception {1}", req.SourceAddress, ex ); return false; } }
public static int Main(string[] args) { bool persistMode = false; int optionIndex = 0; while (optionIndex < args.Length) { if (args[optionIndex] == "/persist") { persistMode = true; } else { break; } optionIndex++; } if (((args.Length - optionIndex) < 1) || (((args.Length - optionIndex - 1) % 2) == 1)) { Console.Error.WriteLine("Usage: SendMap [<option> ...] <exchange-uri> [[<key> <value>] ...]"); Console.Error.WriteLine("RabbitMQ .NET client version "+typeof(IModel).Assembly.GetName().Version.ToString()); Console.Error.WriteLine("Exchange-URI: amqp://host[:port]/exchange[/routingkey][?type=exchangetype]"); Console.Error.WriteLine("Keys must start with '+' or with '-'. Those starting with '+' are placed in"); Console.Error.WriteLine("the body of the message, and those starting with '-' are placed in the headers."); Console.Error.WriteLine("Values must start with a single character typecode and a colon."); Console.Error.WriteLine("Supported typecodes are:"); Console.Error.WriteLine(" S - string/byte array"); Console.Error.WriteLine(" x - byte array (base-64)"); Console.Error.WriteLine(" t - boolean"); Console.Error.WriteLine(" i - 32-bit integer"); Console.Error.WriteLine(" d - double-precision float"); Console.Error.WriteLine(" D - fixed-point decimal"); Console.Error.WriteLine("Note that some types are valid only in the body of a message, and some are"); Console.Error.WriteLine("valid only in the headers."); Console.Error.WriteLine("The exchange \"amq.default\" is an alias for the default (\"\") AMQP exchange,"); Console.Error.WriteLine("introduced so that the default exchange can be addressed via URI syntax."); Console.Error.WriteLine("Available options:"); Console.Error.WriteLine(" /persist send message in 'persistent' mode"); return 2; } Uri uri = new Uri(args[optionIndex++]); string exchange = uri.Segments[1].TrimEnd(new char[] { '/' }); string exchangeType = uri.Query.StartsWith("?type=") ? uri.Query.Substring(6) : null; string routingKey = uri.Segments.Length > 2 ? uri.Segments[2] : ""; if (exchange == "amq.default") { exchange = ""; } ConnectionFactory cf = new ConnectionFactory(); cf.Endpoint = new AmqpTcpEndpoint(uri); using (IConnection conn = cf.CreateConnection()) { using (IModel ch = conn.CreateModel()) { if (exchangeType != null) { ch.ExchangeDeclare(exchange, exchangeType); } IMapMessageBuilder b = new MapMessageBuilder(ch); while ((optionIndex + 1) < args.Length) { string keyAndDiscriminator = args[optionIndex++]; string valueAndType = args[optionIndex++]; if (keyAndDiscriminator.Length < 1) { Console.Error.WriteLine("Invalid key: '{0}'", keyAndDiscriminator); return 2; } string key = keyAndDiscriminator.Substring(1); char discriminator = keyAndDiscriminator[0]; IDictionary target; switch (discriminator) { case '-': target = b.Headers; break; case '+': target = b.Body; break; default: Console.Error.WriteLine("Invalid key: '{0}'", keyAndDiscriminator); return 2; } if (valueAndType.Length < 2 || valueAndType[1] != ':') { Console.Error.WriteLine("Invalid value: '{0}'", valueAndType); return 2; } string valueStr = valueAndType.Substring(2); char typeCode = valueAndType[0]; object value; switch (typeCode) { case 'S': value = valueStr; break; case 'x': value = new BinaryTableValue(Convert.FromBase64String(valueStr)); break; case 't': value = (valueStr.ToLower() == "true" || valueStr.ToLower() == "yes" || valueStr.ToLower() == "on" || valueStr == "1"); break; case 'i': value = int.Parse(valueStr); break; case 'd': value = double.Parse(valueStr); break; case 'D': value = decimal.Parse(valueStr); break; default: Console.Error.WriteLine("Invalid type code: '{0}'", typeCode); return 2; } target[key] = value; } if (persistMode) { ((IBasicProperties) b.GetContentHeader()).DeliveryMode = 2; } ch.BasicPublish(exchange, routingKey, (IBasicProperties) b.GetContentHeader(), b.GetContentBody()); return 0; } } }