fix for: https://issues.apache.org/activemq/browse/AMQNET-271
diff --git a/src/main/csharp/IConnection.cs b/src/main/csharp/IConnection.cs
index 217f87e..0377083 100644
--- a/src/main/csharp/IConnection.cs
+++ b/src/main/csharp/IConnection.cs
@@ -83,7 +83,7 @@
     /// clients that the Connection that was interrupted has now been restored.
     /// </summary>
     public delegate void ConnectionResumedListener();
-
+	
     /// <summary>
     /// Represents a connection with a message broker
     /// </summary>
@@ -120,6 +120,30 @@
         /// has been resumed.
         /// </summary>
         event ConnectionResumedListener ConnectionResumedListener;
+		
+        /// <summary>
+        /// A Delegate that is called each time a Message is dispatched to allow the client to do
+        /// any necessary transformations on the received message before it is delivered.  The
+        /// Connection sets the provided delegate instance on each Session it creates which then
+        /// passes that along to the Consumers it creates.
+        /// </summary>
+        ConsumerTransformerDelegate ConsumerTransformer
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// A delegate that is called each time a Message is sent from this Producer which allows
+        /// the application to perform any needed transformations on the Message before it is sent.
+        /// The Connection sets the provided delegate instance on each Session it creates which then
+        /// passes that along to the Producer it creates.
+        /// </summary>
+        ProducerTransformerDelegate ProducerTransformer
+        {
+            get;
+            set;
+        }
 
         #region Attributes
 
diff --git a/src/main/csharp/IConnectionFactory.cs b/src/main/csharp/IConnectionFactory.cs
index 18529b0..c2956d5 100644
--- a/src/main/csharp/IConnectionFactory.cs
+++ b/src/main/csharp/IConnectionFactory.cs
@@ -44,5 +44,31 @@
         /// assigned upon creation.
         /// </summary>
         IRedeliveryPolicy RedeliveryPolicy{ get; set; }
+
+        /// <summary>
+        /// A Delegate that is called each time a Message is dispatched to allow the client to do
+        /// any necessary transformations on the received message before it is delivered.  The
+        /// ConnectionFactory sets the provided delegate instance on each Connection instance that
+        /// is created from this factory, each connection in turn passes the delegate along to each
+        /// Session it creates which then passes that along to the Consumers it creates.
+        /// </summary>
+        ConsumerTransformerDelegate ConsumerTransformer
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// A delegate that is called each time a Message is sent from this Producer which allows
+        /// the application to perform any needed transformations on the Message before it is sent.
+        /// The ConnectionFactory sets the provided delegate instance on each Connection instance that
+        /// is created from this factory, each connection in turn passes the delegate along to each
+        /// Session it creates which then passes that along to the Producers it creates.
+        /// </summary>
+        ProducerTransformerDelegate ProducerTransformer
+        {
+            get;
+            set;
+        }
 	}
 }
diff --git a/src/main/csharp/IMessageConsumer.cs b/src/main/csharp/IMessageConsumer.cs
index 060281c..4ad781d 100644
--- a/src/main/csharp/IMessageConsumer.cs
+++ b/src/main/csharp/IMessageConsumer.cs
@@ -21,12 +21,22 @@
 	/// </summary>
 	public delegate void MessageListener(IMessage message);
 
+    /// <summary>
+    /// A delegate that a client can register that will be called each time a consumer dispatches a message
+    /// to the client code to allow the client to Transform a received message from one type to another,
+    /// StreamMessage to TextMessage, ObjectMessage to TextMessage containing XML, etc.  This allows a
+    /// client to create a consumer that will automatically transform a message to a type that the client is
+    /// capable of processing or adding additional information to a received message.  For messages that do
+    /// not need to be processed the client should return null from this method, in this case the original
+    /// message will be dispatched to the client.
+    /// </summary>
+    public delegate IMessage ConsumerTransformerDelegate(ISession session, IMessageConsumer consumer, IMessage message);
+
 	/// <summary>
 	/// A consumer of messages
 	/// </summary>
 	public interface IMessageConsumer : System.IDisposable
 	{
-		
 		/// <summary>
 		/// Waits until a message is available and returns it
 		/// </summary>
@@ -56,7 +66,18 @@
 		/// A blocked message consumer receive call returns null when this message consumer is closed.
 		/// </remarks>
 		void Close();
-	}
+
+        /// <summary>
+        /// A Delegate that is called each time a Message is dispatched to allow the client to do
+        /// any necessary transformations on the received message before it is delivered.
+        /// </summary>
+        ConsumerTransformerDelegate ConsumerTransformer
+        {
+            get;
+            set;
+        }
+
+    }
 }
 
 
diff --git a/src/main/csharp/IMessageProducer.cs b/src/main/csharp/IMessageProducer.cs
index a4341e9..b009f39 100644
--- a/src/main/csharp/IMessageProducer.cs
+++ b/src/main/csharp/IMessageProducer.cs
@@ -18,6 +18,17 @@
 
 namespace Apache.NMS
 {
+    /// <summary>
+    /// A delegate that a client can register that will be called each time a Producer's send method is
+    /// called to allow the client to Transform a sent message from one type to another, StreamMessage to
+    /// TextMessage, ObjectMessage to TextMessage containing XML, etc.  This allows a client to create a
+    /// producer that will automatically transform a message to a type that some receiving client is
+    /// capable of processing or adding additional information to a sent message such as additional message
+    /// headers, etc.  For messages that do not need to be processed the client should return null from
+    /// this method, in this case the original message will be sent.
+    /// </summary>
+    public delegate IMessage ProducerTransformerDelegate(ISession session, IMessageProducer producer, IMessage message);
+
 	/// <summary>
 	/// An object capable of sending messages to some destination
 	/// </summary>
@@ -48,6 +59,16 @@
 		/// </summary>
 		void Close();
 
+        /// <summary>
+        /// A delegate that is called each time a Message is sent from this Producer which allows
+        /// the application to perform any needed transformations on the Message before it is sent.
+        /// </summary>
+        ProducerTransformerDelegate ProducerTransformer
+        {
+            get;
+            set;
+        }
+
 		MsgDeliveryMode DeliveryMode { get; set; }
 
 		TimeSpan TimeToLive { get; set; }
diff --git a/src/main/csharp/ISession.cs b/src/main/csharp/ISession.cs
index ad430be..b12f4dc 100644
--- a/src/main/csharp/ISession.cs
+++ b/src/main/csharp/ISession.cs
@@ -23,7 +23,7 @@
 	/// So the ISession can be used to perform transactional receive and sends
 	/// </summary>
 	public interface ISession : IDisposable
-	{
+	{		
 		/// <summary>
 		/// Creates a producer of messages
 		/// </summary>
@@ -165,6 +165,28 @@
 		/// </summary>
 		void Close();
 
+        /// <summary>
+        /// A Delegate that is called each time a Message is dispatched to allow the client to do
+        /// any necessary transformations on the received message before it is delivered.
+        /// The Session instance sets the delegate on each Consumer it creates.
+        /// </summary>
+        ConsumerTransformerDelegate ConsumerTransformer
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// A delegate that is called each time a Message is sent from this Producer which allows
+        /// the application to perform any needed transformations on the Message before it is sent.
+        /// The Session instance sets the delegate on each Producer it creates.
+        /// </summary>
+        ProducerTransformerDelegate ProducerTransformer
+        {
+            get;
+            set;
+        }
+
 		#region Transaction methods
 
 		/// <summary>
diff --git a/src/main/csharp/NMSConnectionFactory.cs b/src/main/csharp/NMSConnectionFactory.cs
index ee51a8e..402fc58 100644
--- a/src/main/csharp/NMSConnectionFactory.cs
+++ b/src/main/csharp/NMSConnectionFactory.cs
@@ -397,5 +397,24 @@
 			set { this.factory.RedeliveryPolicy = value; }

 		}

 

+        /// <summary>

+        /// Get/or Set the ConsumerTransformerDelegate using the IConnectionFactory implementation

+        /// that is currently being used.

+        /// </summary>

+        public ConsumerTransformerDelegate ConsumerTransformer

+        {

+            get { return this.factory.ConsumerTransformer; }

+            set { this.factory.ConsumerTransformer = value; }

+        }

+

+        /// <summary>

+        /// Get/or Set the ProducerTransformerDelegate using the IConnectionFactory implementation

+        /// that is currently being used.

+        /// </summary>

+        public ProducerTransformerDelegate ProducerTransformer

+        {

+            get { return this.factory.ProducerTransformer; }

+            set { this.factory.ProducerTransformer = value; }

+        }

 	}

 }

diff --git a/src/main/csharp/Util/MessageTransformation.cs b/src/main/csharp/Util/MessageTransformation.cs
index 1141367..cee5da4 100644
--- a/src/main/csharp/Util/MessageTransformation.cs
+++ b/src/main/csharp/Util/MessageTransformation.cs
@@ -122,14 +122,11 @@
             }
         }
 
-        /**
-         * Copies the standard JMS and user defined properties from the givem
-         * message to the specified message
-         *
-         * @param fromMessage the message to take the properties from
-         * @param toMessage the message to add the properties to
-         * @throws JMSException
-         */
+        /// <summary>
+        /// Copies the standard NMS and user defined properties from the givem
+        /// message to the specified message, the class version transforms the
+        /// Destination instead of just doing a straight copy.
+        /// </summary>
         public virtual void CopyProperties(IMessage fromMessage, IMessage toMessage)
         {
             toMessage.NMSMessageId = fromMessage.NMSMessageId;
@@ -149,6 +146,30 @@
             }
         }
 
+        /// <summary>
+        /// Copies the standard NMS and user defined properties from the givem
+        /// message to the specified message, this method makes no attempt to convert
+        /// the values in the Message to native provider implementations.
+        /// </summary>
+        public static void CopyNMSMessageProperties(IMessage fromMessage, IMessage toMessage)
+        {
+            toMessage.NMSMessageId = fromMessage.NMSMessageId;
+            toMessage.NMSCorrelationID = fromMessage.NMSCorrelationID;
+            toMessage.NMSReplyTo = fromMessage.NMSReplyTo;
+            toMessage.NMSDestination = fromMessage.NMSDestination;
+            toMessage.NMSDeliveryMode = fromMessage.NMSDeliveryMode;
+            toMessage.NMSRedelivered = fromMessage.NMSRedelivered;
+            toMessage.NMSType = fromMessage.NMSType;
+            toMessage.NMSPriority = fromMessage.NMSPriority;
+            toMessage.NMSTimestamp = fromMessage.NMSTimestamp;
+            toMessage.NMSTimeToLive = fromMessage.NMSTimeToLive;
+
+            foreach(string key in fromMessage.Properties.Keys)
+            {
+                toMessage.Properties[key] = fromMessage.Properties[key];
+            }
+        }
+
         #region Creation Methods and Conversion Support Methods
 
         protected abstract IMessage DoCreateMessage();
diff --git a/src/test/csharp/MessageTransformerTest.cs b/src/test/csharp/MessageTransformerTest.cs
new file mode 100644
index 0000000..992fdc3
--- /dev/null
+++ b/src/test/csharp/MessageTransformerTest.cs
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+using Apache.NMS.Util;
+
+using NUnit.Framework;
+
+namespace Apache.NMS.Test
+{
+	[TestFixture]
+	public class MessageTransformerTest : NMSTestSupport
+	{
+		private string propertyName = "ADDITIONAL-PROPERTY";
+		private string propertyValue = "ADDITIONAL-PROPERTY-VALUE";
+				
+		[Test]
+		public void TestProducerTransformer(
+			[Values(MsgDeliveryMode.Persistent, MsgDeliveryMode.NonPersistent)]
+			MsgDeliveryMode deliveryMode)
+		{
+			using(IConnection connection = CreateConnection())
+			{
+				connection.Start();
+				using(ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge))
+				{
+					IDestination destination = session.CreateTemporaryTopic();
+					using(IMessageConsumer consumer = session.CreateConsumer(destination))
+					using(IMessageProducer producer = session.CreateProducer(destination))
+					{
+						producer.DeliveryMode = deliveryMode;
+						producer.ProducerTransformer = DoProducerTransform;
+
+                        IMessage message = session.CreateMessage();
+
+                        message.Properties["Test"] = "Value";
+
+                        producer.Send(message);
+
+                        message = consumer.Receive(TimeSpan.FromMilliseconds(5000));
+
+                        Assert.IsNotNull(message);
+                        Assert.IsTrue(message.Properties.Count == 2);
+
+                        Assert.AreEqual("Value", message.Properties["Test"]);
+                        Assert.AreEqual(propertyValue, message.Properties[propertyName]);
+					}
+				}
+			}
+		}
+		
+		[Test]
+		public void TestConsumerTransformer(
+			[Values(MsgDeliveryMode.Persistent, MsgDeliveryMode.NonPersistent)]
+			MsgDeliveryMode deliveryMode)
+		{
+			using(IConnection connection = CreateConnection())
+			{
+				connection.Start();
+				using(ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge))
+				{
+					IDestination destination = session.CreateTemporaryTopic();
+					using(IMessageConsumer consumer = session.CreateConsumer(destination))
+					using(IMessageProducer producer = session.CreateProducer(destination))
+					{
+						producer.DeliveryMode = deliveryMode;
+
+						consumer.ConsumerTransformer = DoConsumerTransform;
+
+                        IMessage message = session.CreateMessage();
+
+                        message.Properties["Test"] = "Value";
+
+                        producer.Send(message);
+
+                        message = consumer.Receive(TimeSpan.FromMilliseconds(5000));
+
+                        Assert.IsNotNull(message);
+                        Assert.IsTrue(message.Properties.Count == 2, "Property Count should be 2");
+
+                        Assert.AreEqual("Value", message.Properties["Test"], "Propert 'Value' was incorrect");
+                        Assert.AreEqual(propertyValue, message.Properties[propertyName], "Property not inserted");
+                    }
+				}
+			}
+		}
+		
+		private IMessage DoProducerTransform(ISession session, IMessageProducer producer, IMessage message)
+		{
+			message.Properties[propertyName] = propertyValue;
+			
+			return message;
+		}
+
+		private IMessage DoConsumerTransform(ISession session, IMessageConsumer consumer, IMessage message)
+		{
+            IMessage newMessage = session.CreateMessage();
+
+            MessageTransformation.CopyNMSMessageProperties(message, newMessage);
+
+			newMessage.Properties[propertyName] = propertyValue;
+
+			return newMessage;
+		}
+	}
+}
+