You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by mi...@apache.org on 2021/02/09 17:12:08 UTC

[activemq-nms-amqp] branch 2.0.x updated: AMQNET-637 More async methods implementations, refactors and increase AMQPNetLite.Core version

This is an automated email from the ASF dual-hosted git repository.

michaelpearce pushed a commit to branch 2.0.x
in repository https://gitbox.apache.org/repos/asf/activemq-nms-amqp.git


The following commit(s) were added to refs/heads/2.0.x by this push:
     new 62f26c0  AMQNET-637 More async methods implementations, refactors and increase AMQPNetLite.Core version
     new a2a9d8b  Merge pull request #61 from lukeabsent/AMQNET-637
62f26c0 is described below

commit 62f26c0ed19bc71fc1e2101826e9c1b3c994dec0
Author: lukeabsent <tr...@interia.pl>
AuthorDate: Tue Feb 9 16:28:42 2021 +0100

    AMQNET-637 More async methods implementations, refactors and increase AMQPNetLite.Core version
---
 src/NMS.AMQP/Apache-NMS-AMQP.csproj                |    2 +-
 src/NMS.AMQP/INmsTransactionContext.cs             |    1 -
 src/NMS.AMQP/Message/NmsMessage.cs                 |    9 +-
 src/NMS.AMQP/NmsAcknowledgeCallback.cs             |    8 +-
 src/NMS.AMQP/NmsConnection.cs                      |  113 +-
 src/NMS.AMQP/NmsConnectionFactory.cs               |   32 +
 src/NMS.AMQP/NmsConsumer.cs                        |   26 +
 src/NMS.AMQP/NmsContext.cs                         |  238 +++-
 src/NMS.AMQP/NmsLocalTransactionContext.cs         |   21 +-
 src/NMS.AMQP/NmsMessageConsumer.cs                 |  175 ++-
 src/NMS.AMQP/NmsMessageProducer.cs                 |   17 +-
 src/NMS.AMQP/NmsNoTxTransactionContext.cs          |    1 -
 src/NMS.AMQP/NmsProducer.cs                        |    8 +-
 src/NMS.AMQP/NmsQueueBrowser.cs                    |   26 +-
 src/NMS.AMQP/NmsSession.cs                         |  257 +++-
 src/NMS.AMQP/NmsTemporaryDestination.cs            |   10 +-
 src/NMS.AMQP/Provider/Amqp/AmqpConnection.cs       |   25 +-
 .../Provider/Amqp/AmqpConnectionSession.cs         |    5 +-
 src/NMS.AMQP/Provider/Amqp/AmqpConsumer.cs         |    7 +-
 src/NMS.AMQP/Provider/Amqp/AmqpProducer.cs         |   13 +-
 src/NMS.AMQP/Provider/Amqp/AmqpProvider.cs         |   30 +-
 src/NMS.AMQP/Provider/Amqp/AmqpSendTask.cs         |    3 +-
 src/NMS.AMQP/Provider/Amqp/AmqpSession.cs          |   11 +-
 .../Provider/Amqp/AmqpTemporaryDestination.cs      |    7 +-
 .../Provider/Amqp/AmqpTransactionContext.cs        |   12 +-
 .../Provider/Amqp/AmqpTransactionCoordinator.cs    |    5 +-
 src/NMS.AMQP/Provider/Failover/FailoverProvider.cs |   50 +-
 src/NMS.AMQP/Provider/Failover/FailoverRequest.cs  |    3 +-
 src/NMS.AMQP/Provider/IProvider.cs                 |    1 +
 src/NMS.AMQP/SessionDispatcher.cs                  |   13 +-
 src/NMS.AMQP/Util/PriorityMessageQueue.cs          |   73 +-
 src/NMS.AMQP/Util/SymbolUtil.cs                    |    7 +-
 .../Synchronization/NmsSynchronizationMonitor.cs   |  280 ++++
 .../Util/Synchronization/TaskExtensions.cs         |   66 +
 .../Synchronization/TaskSynchronizationSettings.cs |   38 +
 src/NMS.AMQP/Util/UriUtil.cs                       |    5 -
 .../Transactions/NmsTransactedConsumerTest.cs      |    2 +
 .../AmqpAcknowledgmentsIntegrationTest.cs          |    1 +
 .../AmqpAcknowledgmentsIntegrationTest.cs          |  123 +-
 .../Integration/Async/ConnectionIntegrationTest.cs |  254 ++++
 .../{ => Async}/ConsumerIntegrationTest.cs         |  360 ++---
 .../Integration/Async/FailoverIntegrationTest.cs   | 1164 ++++++++++++++++
 .../{ => Async}/MessageDeliveryTimeTest.cs         |   71 +-
 .../Async/MessageExpirationIntegrationTest.cs      |  252 ++++
 .../{ => Async}/NMSConsumerIntegrationTest.cs      |  380 +++--
 .../Integration/Async/NMSContextIntegrationTest.cs |  279 ++++
 .../Async/NMSProducerIntegrationTest.cs            |  723 ++++++++++
 .../Async/ProducerIntegrationAsyncTest.cs          |  135 ++
 .../Integration/Async/ProducerIntegrationTest.cs   |  782 +++++++++++
 .../Integration/Async/SessionIntegrationTest.cs    |  289 ++++
 .../Async/SubscriptionsIntegrationTest.cs          |   74 +
 .../Async/TemporaryQueueIntegrationTest.cs         |   88 ++
 .../Async/TemporaryTopicIntegrationTest.cs         |   89 ++
 .../Async/TransactionsIntegrationTest.cs           | 1473 ++++++++++++++++++++
 .../Integration/ConsumerIntegrationTest.cs         |    2 +
 .../Integration/IntegrationTestFixture.cs          |   25 +-
 .../Integration/MessageDeliveryTimeTest.cs         |    2 +-
 .../Integration/NMSConsumerIntegrationTest.cs      |   90 +-
 .../Message/Facade/AmqpNmsMessageFacadeTest.cs     |   29 +
 .../Message/Foreign/ForeignNmsMessage.cs           |    6 +
 .../Provider/Mock/MockProvider.cs                  |    5 +
 .../TestAmqp/TestAmqpPeerRunner.cs                 |    8 +-
 .../NmsSynchronizationMonitorTest.cs               |  437 ++++++
 63 files changed, 7994 insertions(+), 747 deletions(-)

diff --git a/src/NMS.AMQP/Apache-NMS-AMQP.csproj b/src/NMS.AMQP/Apache-NMS-AMQP.csproj
index 7b4ac02..3bdba18 100644
--- a/src/NMS.AMQP/Apache-NMS-AMQP.csproj
+++ b/src/NMS.AMQP/Apache-NMS-AMQP.csproj
@@ -80,7 +80,7 @@ with the License.  You may obtain a copy of the License at
 
     <ItemGroup>
         <!-- AMQPNetLite.Core is .NET Standard 1.3 package -->
-        <PackageReference Include="AMQPNetLite.Core" Version="2.4.0" />
+        <PackageReference Include="AMQPNetLite.Core" Version="2.4.1" />
         <PackageReference Include="Apache.NMS" Version="2.0.0" />
         <PackageReference Include="System.Threading.Tasks.Dataflow" Version="4.9.0" />
     </ItemGroup>
diff --git a/src/NMS.AMQP/INmsTransactionContext.cs b/src/NMS.AMQP/INmsTransactionContext.cs
index 6b8f6b1..7bcfaf9 100644
--- a/src/NMS.AMQP/INmsTransactionContext.cs
+++ b/src/NMS.AMQP/INmsTransactionContext.cs
@@ -19,7 +19,6 @@ using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
-using Apache.NMS.AMQP.Util;
 
 namespace Apache.NMS.AMQP
 {
diff --git a/src/NMS.AMQP/Message/NmsMessage.cs b/src/NMS.AMQP/Message/NmsMessage.cs
index 1ca0f14..c56854c 100644
--- a/src/NMS.AMQP/Message/NmsMessage.cs
+++ b/src/NMS.AMQP/Message/NmsMessage.cs
@@ -16,7 +16,9 @@
  */
 
 using System;
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message.Facade;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP.Message
@@ -150,11 +152,16 @@ namespace Apache.NMS.AMQP.Message
 
         public void Acknowledge()
         {
+            AcknowledgeAsync().GetAsyncResult();
+        }
+
+        public async Task AcknowledgeAsync()
+        {
             if (NmsAcknowledgeCallback != null)
             {
                 try
                 {
-                    NmsAcknowledgeCallback.Acknowledge();
+                    await NmsAcknowledgeCallback.Acknowledge().Await();
                     NmsAcknowledgeCallback = null;
                 }
                 catch (Exception e)
diff --git a/src/NMS.AMQP/NmsAcknowledgeCallback.cs b/src/NMS.AMQP/NmsAcknowledgeCallback.cs
index 40364c6..fefb32d 100644
--- a/src/NMS.AMQP/NmsAcknowledgeCallback.cs
+++ b/src/NMS.AMQP/NmsAcknowledgeCallback.cs
@@ -15,8 +15,10 @@
  * limitations under the License.
  */
 
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
@@ -32,7 +34,7 @@ namespace Apache.NMS.AMQP
             this.envelope = envelope;
         }
 
-        public void Acknowledge()
+        public async Task Acknowledge()
         {
             if (session.IsClosed)
             {
@@ -41,11 +43,11 @@ namespace Apache.NMS.AMQP
 
             if (envelope == null)
             {
-                session.Acknowledge(AcknowledgementType);
+                await session.AcknowledgeAsync(AcknowledgementType).Await();
             }
             else
             {
-                session.AcknowledgeIndividual(AcknowledgementType, envelope);
+                await session.AcknowledgeIndividualAsync(AcknowledgementType, envelope).Await();
             }
         }
 
diff --git a/src/NMS.AMQP/NmsConnection.cs b/src/NMS.AMQP/NmsConnection.cs
index 9ecffa9..e0a98d8 100644
--- a/src/NMS.AMQP/NmsConnection.cs
+++ b/src/NMS.AMQP/NmsConnection.cs
@@ -25,6 +25,7 @@ using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP
@@ -43,7 +44,7 @@ namespace Apache.NMS.AMQP
         private readonly AtomicLong temporaryQueueIdGenerator = new AtomicLong();
         private readonly AtomicLong transactionIdGenerator = new AtomicLong();
         private Exception failureCause;
-        private readonly object syncRoot = new object();
+        private readonly NmsSynchronizationMonitor syncRoot = new NmsSynchronizationMonitor();
 
         public NmsConnection(NmsConnectionInfo connectionInfo, IProvider provider)
         {
@@ -89,12 +90,18 @@ namespace Apache.NMS.AMQP
             DoStop(true);
         }
 
+        public Task StopAsync()
+        {
+            Stop();
+            return Task.CompletedTask;
+        }
+
         private void DoStop(bool checkClosed)
         {
             if (checkClosed)
                 CheckClosedOrFailed();
 
-            CheckIsOnDeliveryThread();
+            CheckIsOnDeliveryExecutionFlow();
 
             if (started.CompareAndSet(true, false))
             {
@@ -112,13 +119,23 @@ namespace Apache.NMS.AMQP
 
         public ISession CreateSession(AcknowledgementMode acknowledgementMode)
         {
+            return CreateSessionAsync(acknowledgementMode).GetAsyncResult();
+        }
+
+        public Task<ISession> CreateSessionAsync()
+        {
+            return CreateSessionAsync(AcknowledgementMode);
+        }
+
+        public async Task<ISession> CreateSessionAsync(AcknowledgementMode acknowledgementMode)
+        {
             CheckClosedOrFailed();
-            CreateNmsConnection();
+            await CreateNmsConnectionAsync().Await();
 
             NmsSession session = new NmsSession(this, GetNextSessionId(), acknowledgementMode);
             try
             {
-                session.Begin().ConfigureAwait(false).GetAwaiter().GetResult();
+                await session.Begin().Await();
                 sessions.TryAdd(session.SessionInfo.Id, session);
                 if (started)
                 {
@@ -139,18 +156,23 @@ namespace Apache.NMS.AMQP
 
         public void Close()
         {
-            CheckIsOnDeliveryThread();
+            CloseAsync().GetAsyncResult();
+        }
+
+        public async Task CloseAsync()
+        {
+            CheckIsOnDeliveryExecutionFlow();
 
             if (closed.CompareAndSet(false, true))
             {
                 DoStop(false);
 
                 foreach (NmsSession session in sessions.Values)
-                    session.Shutdown(null);
+                    await session.ShutdownAsync(null).Await();;
 
                 try
                 {
-                    provider.Close();
+                    await provider.CloseAsync().Await();;
                 }
                 catch (Exception)
                 {
@@ -170,7 +192,12 @@ namespace Apache.NMS.AMQP
 
         public void Start()
         {
-            CreateNmsConnection();
+            StartAsync().GetAsyncResult();
+        }
+        
+        public async Task StartAsync()
+        {
+            await CreateNmsConnectionAsync().Await();;
 
             if (started.CompareAndSet(false, true))
             {
@@ -288,12 +315,12 @@ namespace Apache.NMS.AMQP
         {
             foreach (NmsTemporaryDestination tempDestination in tempDestinations.Values)
             {
-                await provider.CreateResource(tempDestination);
+                await provider.CreateResource(tempDestination).Await();;
             }
 
             foreach (NmsSession session in sessions.Values)
             {
-                await session.OnConnectionRecovery(provider).ConfigureAwait(false);
+                await session.OnConnectionRecovery(provider).Await();
             }
         }
 
@@ -314,7 +341,7 @@ namespace Apache.NMS.AMQP
 
             foreach (NmsSession session in sessions.Values)
             {
-                await session.OnConnectionRecovered(provider).ConfigureAwait(false);
+                await session.OnConnectionRecovered(provider).Await();
             }
         }
 
@@ -403,38 +430,56 @@ namespace Apache.NMS.AMQP
             return provider.Send(envelope);
         }
 
-        private void CheckIsOnDeliveryThread()
+        private void CheckIsOnDeliveryExecutionFlow()
         {
             foreach (NmsSession session in sessions.Values)
             {
-                session.CheckIsOnDeliveryThread();
+                session.CheckIsOnDeliveryExecutionFlow();
             }
         }
 
         private void CreateNmsConnection()
         {
+            CreateNmsConnectionInternal(true).GetAsyncResult();
+        }
+
+        private Task CreateNmsConnectionAsync()
+        {
+            return CreateNmsConnectionInternal(false);
+        }
+        
+        private async Task CreateNmsConnectionInternal(bool sync = true)
+        {
             if (connected || closed)
             {
                 return;
             }
 
-            lock (syncRoot)
+            var syncLock = sync ? syncRoot.Lock() : await syncRoot.LockAsync();
+            using(syncLock)
             {
                 if (closed || connected)
                 {
                     return;
                 }
-                
+
                 try
                 {
-                    provider.Connect(ConnectionInfo).ConfigureAwait(false).GetAwaiter().GetResult();
+                    var configureTask = provider.Connect(ConnectionInfo).Await();
+                    if (sync)
+                        configureTask.GetAwaiter().GetResult();
+                    else
+                        await configureTask;
                     connected.Set(true);
                 }
                 catch (Exception e)
                 {
                     try
                     {
-                        provider.Close();
+                        if (sync)
+                            provider.Close();
+                        else
+                            await provider.CloseAsync().Await();
                     }
                     catch
                     {
@@ -444,6 +489,7 @@ namespace Apache.NMS.AMQP
                     throw NMSExceptionSupport.Create(e);
                 }
             }
+            
         }
 
         internal void OnAsyncException(Exception error)
@@ -488,23 +534,33 @@ namespace Apache.NMS.AMQP
 
         public ITemporaryQueue CreateTemporaryQueue()
         {
+            return CreateTemporaryQueueAsync().GetAsyncResult();
+        } 
+        
+        public async Task<ITemporaryQueue> CreateTemporaryQueueAsync()
+        {
             var destinationName = $"{Id}:{temporaryQueueIdGenerator.IncrementAndGet().ToString()}";
             var queue = new NmsTemporaryQueue(destinationName);
-            InitializeTemporaryDestination(queue);
+            await InitializeTemporaryDestinationAsync(queue).Await();;
             return queue;
         }
 
         public ITemporaryTopic CreateTemporaryTopic()
         {
+            return CreateTemporaryTopicAsync().GetAsyncResult();
+        } 
+        
+        public async Task<ITemporaryTopic> CreateTemporaryTopicAsync()
+        {
             var destinationName = $"{Id}:{temporaryTopicIdGenerator.IncrementAndGet().ToString()}";
             NmsTemporaryTopic topic = new NmsTemporaryTopic(destinationName);
-            InitializeTemporaryDestination(topic);
+            await InitializeTemporaryDestinationAsync(topic).Await();;
             return topic;
         }
 
-        private void InitializeTemporaryDestination(NmsTemporaryDestination temporaryDestination)
+        private async Task InitializeTemporaryDestinationAsync(NmsTemporaryDestination temporaryDestination)
         {
-            CreateResource(temporaryDestination).ConfigureAwait(false).GetAwaiter().GetResult();
+            await CreateResource(temporaryDestination).Await();
             tempDestinations.TryAdd(temporaryDestination, temporaryDestination);
             temporaryDestination.Connection = this;
         }
@@ -515,7 +571,7 @@ namespace Apache.NMS.AMQP
                 throw new InvalidDestinationException("Can't consume from a temporary destination created using another connection");
         }
 
-        public void DeleteTemporaryDestination(NmsTemporaryDestination destination)
+        public async Task DeleteTemporaryDestinationAsync(NmsTemporaryDestination destination)
         {
             CheckClosedOrFailed();
 
@@ -531,7 +587,7 @@ namespace Apache.NMS.AMQP
 
                 tempDestinations.TryRemove(destination, out _);
 
-                DestroyResource(destination).ConfigureAwait(false).GetAwaiter().GetResult();
+                await DestroyResource(destination).Await();
             }
             catch (Exception e)
             {
@@ -541,11 +597,16 @@ namespace Apache.NMS.AMQP
 
         public void Unsubscribe(string subscriptionName)
         {
-            CheckClosedOrFailed();
-
-            provider.Unsubscribe(subscriptionName).ConfigureAwait(false).GetAwaiter().GetResult();
+            UnsubscribeAsync(subscriptionName).GetAsyncResult();
         }
 
+        public async Task UnsubscribeAsync(string subscriptionName)
+        {
+            CheckClosedOrFailed();
+            
+            await provider.Unsubscribe(subscriptionName).Await();
+        }
+        
         public Task Rollback(NmsTransactionInfo transactionInfo, NmsTransactionInfo nextTransactionInfo)
         {
             return provider.Rollback(transactionInfo, nextTransactionInfo);
diff --git a/src/NMS.AMQP/NmsConnectionFactory.cs b/src/NMS.AMQP/NmsConnectionFactory.cs
index 88101bb..66543df 100644
--- a/src/NMS.AMQP/NmsConnectionFactory.cs
+++ b/src/NMS.AMQP/NmsConnectionFactory.cs
@@ -17,9 +17,11 @@
 
 using System;
 using System.Collections.Specialized;
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 using URISupport = Apache.NMS.AMQP.Util.URISupport;
 
@@ -166,7 +168,17 @@ namespace Apache.NMS.AMQP
         {
             return CreateConnection(UserName, Password);
         }
+        
+        public Task<IConnection> CreateConnectionAsync()
+        {
+            return CreateConnectionAsync(UserName, Password);
+        }
 
+        public Task<IConnection> CreateConnectionAsync(string userName, string password)
+        {
+            return Task.FromResult(CreateConnection(userName, password));
+        }
+       
         public IConnection CreateConnection(string userName, string password)
         {
             try
@@ -201,6 +213,26 @@ namespace Apache.NMS.AMQP
             return new NmsContext((NmsConnection)CreateConnection(userName, password), acknowledgementMode);
         }
 
+        public async Task<INMSContext> CreateContextAsync()
+        {
+            return new NmsContext((NmsConnection)await CreateConnectionAsync().Await(), AcknowledgementMode.AutoAcknowledge);
+        }
+
+        public async Task<INMSContext> CreateContextAsync(AcknowledgementMode acknowledgementMode)
+        {
+            return new NmsContext((NmsConnection)await CreateConnectionAsync().Await(), acknowledgementMode);
+        }
+
+        public async Task<INMSContext> CreateContextAsync(string userName, string password)
+        {
+            return new NmsContext((NmsConnection)await CreateConnectionAsync(userName, password).Await(), AcknowledgementMode.AutoAcknowledge);
+        }
+
+        public async Task<INMSContext> CreateContextAsync(string userName, string password, AcknowledgementMode acknowledgementMode)
+        {
+            return new NmsContext((NmsConnection)await CreateConnectionAsync(userName, password).Await(), acknowledgementMode);
+        }
+
         public Uri BrokerUri
         {
             get => brokerUri;
diff --git a/src/NMS.AMQP/NmsConsumer.cs b/src/NMS.AMQP/NmsConsumer.cs
index 9a2d40d..d6d905b 100644
--- a/src/NMS.AMQP/NmsConsumer.cs
+++ b/src/NMS.AMQP/NmsConsumer.cs
@@ -16,6 +16,7 @@
  */
 
 using System;
+using System.Threading.Tasks;
 
 namespace Apache.NMS.AMQP
 {
@@ -40,11 +41,21 @@ namespace Apache.NMS.AMQP
             return consumer.Receive();
         }
 
+        public Task<IMessage> ReceiveAsync()
+        {
+            return consumer.ReceiveAsync();
+        }
+
         public IMessage Receive(TimeSpan timeout)
         {
             return consumer.Receive(timeout);
         }
 
+        public Task<IMessage> ReceiveAsync(TimeSpan timeout)
+        {
+            return consumer.ReceiveAsync(timeout);
+        }
+
         public IMessage ReceiveNoWait()
         {
             return consumer.ReceiveNoWait();
@@ -55,11 +66,21 @@ namespace Apache.NMS.AMQP
             return consumer.ReceiveBody<T>();
         }
 
+        public Task<T> ReceiveBodyAsync<T>()
+        {
+            return consumer.ReceiveBodyAsync<T>();
+        }
+
         public T ReceiveBody<T>(TimeSpan timeout)
         {
             return consumer.ReceiveBody<T>(timeout);
         }
 
+        public Task<T> ReceiveBodyAsync<T>(TimeSpan timeout)
+        {
+            return consumer.ReceiveBodyAsync<T>(timeout);
+        }
+
         public T ReceiveBodyNoWait<T>()
         {
             return consumer.ReceiveBodyNoWait<T>();
@@ -70,6 +91,11 @@ namespace Apache.NMS.AMQP
             consumer.Close();
         }
 
+        public Task CloseAsync()
+        {
+            return consumer.CloseAsync();
+        }
+
         public string MessageSelector => consumer.MessageSelector;
 
         public ConsumerTransformerDelegate ConsumerTransformer
diff --git a/src/NMS.AMQP/NmsContext.cs b/src/NMS.AMQP/NmsContext.cs
index 260647e..d8b905e 100644
--- a/src/NMS.AMQP/NmsContext.cs
+++ b/src/NMS.AMQP/NmsContext.cs
@@ -16,13 +16,15 @@
  */
 
 using System;
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
     public class NmsContext : INMSContext
     {
-        private readonly object syncRoot = new object();
+        private readonly NmsSynchronizationMonitor syncRoot = new NmsSynchronizationMonitor();
 
         private readonly NmsConnection connection;
         private readonly AtomicLong connectionRefCount;
@@ -57,6 +59,11 @@ namespace Apache.NMS.AMQP
             connection.Start();
         }
 
+        public Task StartAsync()
+        {
+            return connection.StartAsync();
+        }
+
         public bool IsStarted { get => connection.IsStarted; }
         
         public void Stop()
@@ -64,6 +71,11 @@ namespace Apache.NMS.AMQP
             connection.Stop();
         }
 
+        public Task StopAsync()
+        {
+            return connection.StopAsync();
+        }
+
         public INMSContext CreateContext(AcknowledgementMode acknowledgementMode)
         {
             if (connectionRefCount.Get() == 0) {
@@ -76,9 +88,12 @@ namespace Apache.NMS.AMQP
 
         public INMSProducer CreateProducer()
         {
-            if (sharedProducer == null) {
-                lock (syncRoot) {
-                    if (sharedProducer == null) {
+            if (sharedProducer == null)
+            {
+                using(syncRoot.Lock())
+                {
+                    if (sharedProducer == null)
+                    {
                         sharedProducer = (NmsMessageProducer) GetSession().CreateProducer();
                     }
                 }
@@ -86,6 +101,21 @@ namespace Apache.NMS.AMQP
             return new NmsProducer(GetSession(), sharedProducer);
         }
 
+        public async Task<INMSProducer> CreateProducerAsync()
+        {
+            if (sharedProducer == null)
+            {
+                using (await syncRoot.LockAsync().Await())
+                {
+                    if (sharedProducer == null)
+                    {
+                        sharedProducer = (NmsMessageProducer) await (await GetSessionAsync().Await()).CreateProducerAsync().Await();
+                    }
+                }
+            }
+            return new NmsProducer(await GetSessionAsync(), sharedProducer);
+        }
+
 
         public INMSConsumer CreateConsumer(IDestination destination)
         {
@@ -137,96 +167,238 @@ namespace Apache.NMS.AMQP
             return StartIfNeeded(new NmsConsumer(GetSession(), (NmsMessageConsumer) GetSession().CreateSharedDurableConsumer(destination, subscriptionName, selector)));
         }
 
+        public async Task<INMSConsumer> CreateConsumerAsync(IDestination destination)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync().Await(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateConsumerAsync(destination)));
+        }
+
+        public async Task<INMSConsumer> CreateConsumerAsync(IDestination destination, string selector)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync().Await(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateConsumerAsync(destination, selector)));
+        }
+
+        public async Task<INMSConsumer> CreateConsumerAsync(IDestination destination, string selector, bool noLocal)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateConsumerAsync(destination, selector, noLocal)));
+        }
+
+        public async Task<INMSConsumer> CreateDurableConsumerAsync(ITopic destination, string subscriptionName)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateDurableConsumerAsync(destination, subscriptionName)));
+        }
+
+        public async Task<INMSConsumer> CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateDurableConsumerAsync(destination, subscriptionName, selector)));
+        }
+
+        public async Task<INMSConsumer> CreateDurableConsumerAsync(ITopic destination, string subscriptionName, string selector, bool noLocal)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateDurableConsumerAsync(destination, subscriptionName, selector, noLocal)));
+        }
+
+        public async Task<INMSConsumer> CreateSharedConsumerAsync(ITopic destination, string subscriptionName)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateSharedConsumerAsync(destination, subscriptionName)));
+        }
+        
+        public async Task<INMSConsumer> CreateSharedConsumerAsync(ITopic destination, string subscriptionName, string selector)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateSharedConsumerAsync(destination, subscriptionName, selector)));
+        }
+
+        public async Task<INMSConsumer> CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateSharedDurableConsumerAsync(destination, subscriptionName)));
+        }
+
+        public async Task<INMSConsumer> CreateSharedDurableConsumerAsync(ITopic destination, string subscriptionName, string selector)
+        {
+            return await StartIfNeededAsync(new NmsConsumer(await GetSessionAsync(), (NmsMessageConsumer) await (await GetSessionAsync()).CreateSharedDurableConsumerAsync(destination, subscriptionName, selector)));
+        }
+
         public void Unsubscribe(string name)
         {
             GetSession().Unsubscribe(name);
         }
 
+        public async Task UnsubscribeAsync(string name)
+        {
+            await (await GetSessionAsync().Await()).UnsubscribeAsync(name).Await();
+        }
+
         public IQueueBrowser CreateBrowser(IQueue queue)
         {
             return GetSession().CreateBrowser(queue);
         }
 
+        public async Task<IQueueBrowser> CreateBrowserAsync(IQueue queue)
+        {
+            return await (await GetSessionAsync().Await()).CreateBrowserAsync(queue).Await();
+        }
+
         public IQueueBrowser CreateBrowser(IQueue queue, string selector)
         {
             return GetSession().CreateBrowser(queue, selector);
         }
 
+        public async Task<IQueueBrowser> CreateBrowserAsync(IQueue queue, string selector)
+        {
+            return await (await GetSessionAsync().Await()).CreateBrowserAsync(queue, selector).Await();
+        }
+
         public IQueue GetQueue(string name)
         {
             return GetSession().GetQueue(name);
         }
 
+        public async Task<IQueue> GetQueueAsync(string name)
+        {
+            return await (await GetSessionAsync().Await()).GetQueueAsync(name).Await();
+        }
+
         public ITopic GetTopic(string name)
         {
             return GetSession().GetTopic(name);
         }
 
+        public async Task<ITopic> GetTopicAsync(string name)
+        {
+            return await (await GetSessionAsync().Await()).GetTopicAsync(name).Await();
+        }
+
         public ITemporaryQueue CreateTemporaryQueue()
         {
             return GetSession().CreateTemporaryQueue();
         }
 
+        public async Task<ITemporaryQueue> CreateTemporaryQueueAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateTemporaryQueueAsync().Await();
+        }
+
         public ITemporaryTopic CreateTemporaryTopic()
         {
             return GetSession().CreateTemporaryTopic();
         }
 
+        public async Task<ITemporaryTopic> CreateTemporaryTopicAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateTemporaryTopicAsync().Await();
+        }
+
         public IMessage CreateMessage()
         {
             return GetSession().CreateMessage();
         }
 
+        public async Task<IMessage> CreateMessageAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateMessageAsync().Await();
+        }
+
         public ITextMessage CreateTextMessage()
         {
             return GetSession().CreateTextMessage();
         }
 
+        public async Task<ITextMessage> CreateTextMessageAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateTextMessageAsync().Await();
+        }
+
         public ITextMessage CreateTextMessage(string text)
         {
             return GetSession().CreateTextMessage(text);
         }
 
+        public async Task<ITextMessage> CreateTextMessageAsync(string text)
+        {
+            return await (await GetSessionAsync().Await()).CreateTextMessageAsync(text).Await();
+        }
+
         public IMapMessage CreateMapMessage()
         {
             return GetSession().CreateMapMessage();
         }
 
+        public async Task<IMapMessage> CreateMapMessageAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateMapMessageAsync().Await();
+        }
+
         public IObjectMessage CreateObjectMessage(object body)
         {
             return GetSession().CreateObjectMessage(body);
         }
 
+        public async Task<IObjectMessage> CreateObjectMessageAsync(object body)
+        {
+            return await (await GetSessionAsync().Await()).CreateObjectMessageAsync(body).Await();
+        }
+
         public IBytesMessage CreateBytesMessage()
         {
             return GetSession().CreateBytesMessage();
         }
 
+        public async Task<IBytesMessage> CreateBytesMessageAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateBytesMessageAsync().Await();
+        }
+
         public IBytesMessage CreateBytesMessage(byte[] body)
         {
             return GetSession().CreateBytesMessage(body);
         }
 
+        public async Task<IBytesMessage> CreateBytesMessageAsync(byte[] body)
+        {
+            return await (await GetSessionAsync().Await()).CreateBytesMessageAsync(body).Await();
+        }
+
         public IStreamMessage CreateStreamMessage()
         {
             return GetSession().CreateStreamMessage();
         }
 
+        public async Task<IStreamMessage> CreateStreamMessageAsync()
+        {
+            return await (await GetSessionAsync().Await()).CreateStreamMessageAsync().Await();
+        }
+
         public void Close()
         {
+            CloseInternal(true).GetAsyncResult();
+        }
+
+        public Task CloseAsync()
+        {
+            return CloseInternal(false);
+        }
+
+        public async Task CloseInternal(bool sync)
+        {
             NMSException failure = null;
 
             try
             {
-                session?.Close();
+                if (sync)
+                    session?.Close();
+                else
+                    await (session?.CloseAsync() ?? Task.CompletedTask).Await();
             } catch (NMSException jmse)
             {
                 failure = jmse;
             }
 
             if (connectionRefCount.DecrementAndGet() == 0) {
-                try {
-                    connection.Close();
+                try
+                {
+                    if (sync)
+                        connection.Close();
+                    else
+                        await connection.CloseAsync().Await();
                 } catch (NMSException jmse) {
                     if (failure == null)
                     {
@@ -239,27 +411,48 @@ namespace Apache.NMS.AMQP
                 throw failure;
             }
         }
-
+        
+        
         public void Recover()
         {
             GetSession().Recover();
         }
 
+        public async Task RecoverAsync()
+        {
+            await (await GetSessionAsync().Await()).RecoverAsync().Await();
+        }
+
         public void Acknowledge()
         {
             GetSession().Acknowledge();
         }
 
+        public async Task AcknowledgeAsync()
+        {
+            await (await GetSessionAsync().Await()).AcknowledgeAsync().Await();
+        }
+
         public void Commit()
         {
             GetSession().Commit();
         }
 
+        public async Task CommitAsync()
+        {
+            await (await GetSessionAsync().Await()).CommitAsync().Await();
+        }
+
         public void Rollback()
         {
             GetSession().Rollback();
         }
 
+        public async Task RollbackAsync()
+        {
+            await (await GetSessionAsync().Await()).RollbackAsync().Await();
+        }
+
         public void PurgeTempDestinations()
         {
             connection.PurgeTempDestinations();
@@ -267,8 +460,10 @@ namespace Apache.NMS.AMQP
         
         
         private NmsSession GetSession() {
-            if (session == null) {
-                lock (syncRoot) {
+            if (session == null)
+            {
+                using( syncRoot.Lock())
+                {
                     if (session == null)
                     {
                         session = (NmsSession) connection.CreateSession(AcknowledgementMode);
@@ -277,6 +472,22 @@ namespace Apache.NMS.AMQP
             }
             return session;
         }
+
+        private async Task<NmsSession> GetSessionAsync()
+        {
+            if (session == null)
+            {
+                using(await syncRoot.LockAsync().Await())
+                {
+                    if (session == null)
+                    {
+                        session = (NmsSession) await connection.CreateSessionAsync(AcknowledgementMode).Await();
+                    }
+                }
+            }
+
+            return session;
+        }
         
         private NmsConsumer StartIfNeeded(NmsConsumer consumer) {
             if (autoStart) {
@@ -285,6 +496,13 @@ namespace Apache.NMS.AMQP
             return consumer;
         }
         
+        private async Task<NmsConsumer> StartIfNeededAsync(NmsConsumer consumer) {
+            if (autoStart) {
+                await connection.StartAsync().Await();
+            }
+            return consumer;
+        }
+        
 
         public ConsumerTransformerDelegate ConsumerTransformer { get => session.ConsumerTransformer; set => session.ConsumerTransformer = value; }
         
diff --git a/src/NMS.AMQP/NmsLocalTransactionContext.cs b/src/NMS.AMQP/NmsLocalTransactionContext.cs
index caae980..58995f8 100644
--- a/src/NMS.AMQP/NmsLocalTransactionContext.cs
+++ b/src/NMS.AMQP/NmsLocalTransactionContext.cs
@@ -23,6 +23,7 @@ using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP
@@ -47,7 +48,7 @@ namespace Apache.NMS.AMQP
         {
             if (!IsInDoubt())
             {
-                await this.connection.Send(envelope);
+                await this.connection.Send(envelope).Await();
                 this.participants.Add(envelope.ProducerId);
             }
         }
@@ -59,7 +60,7 @@ namespace Apache.NMS.AMQP
             {
                 try
                 {
-                    await this.connection.Acknowledge(envelope, ackType).ConfigureAwait(false);
+                    await this.connection.Acknowledge(envelope, ackType).Await();
                     this.participants.Add(envelope.ConsumerId);
                     Tracer.Debug($"TX:{this.transactionInfo.Id} has performed an acknowledge.");
                 }
@@ -72,7 +73,7 @@ namespace Apache.NMS.AMQP
             }
             else
             {
-                await this.connection.Acknowledge(envelope, ackType).ConfigureAwait(false);
+                await this.connection.Acknowledge(envelope, ackType).Await();
             }
         }
 
@@ -83,7 +84,7 @@ namespace Apache.NMS.AMQP
             try
             {
                 Reset();
-                await this.session.Connection.CreateResource(this.transactionInfo);
+                await this.session.Connection.CreateResource(this.transactionInfo).Await();
                 OnTransactionStarted();
                 Tracer.Debug($"Begin: {this.transactionInfo.Id}");
             }
@@ -120,7 +121,7 @@ namespace Apache.NMS.AMQP
             {
                 this.transactionInfo = GetNextTransactionInfo();
                 Tracer.Debug($"Transaction recovery creating new TX:{this.transactionInfo.Id} after failover.");
-                await provider.CreateResource(this.transactionInfo).ConfigureAwait(false);
+                await provider.CreateResource(this.transactionInfo).Await();
             }
         }
 
@@ -141,7 +142,7 @@ namespace Apache.NMS.AMQP
             {
                 try
                 {
-                    await Rollback();
+                    await Rollback().Await();
                 }
                 catch (Exception e)
                 {
@@ -157,7 +158,7 @@ namespace Apache.NMS.AMQP
 
             try
             {
-                await this.connection.Commit(this.transactionInfo, nextTx).ConfigureAwait(false);
+                await this.connection.Commit(this.transactionInfo, nextTx).Await();
                 OnTransactionCommitted();
                 Reset();
                 this.transactionInfo = nextTx;
@@ -180,7 +181,7 @@ namespace Apache.NMS.AMQP
                     // one to recover our state.
                     if (nextTx.ProviderTxId == null)
                     {
-                        await Begin().ConfigureAwait(false);
+                        await Begin().Await();
                     }
                 }
                 catch (Exception e)
@@ -202,7 +203,7 @@ namespace Apache.NMS.AMQP
 
             try
             {
-                await this.connection.Rollback(this.transactionInfo, nextTx);
+                await this.connection.Rollback(this.transactionInfo, nextTx).Await();
                 OnTransactionRolledBack();
                 Reset();
                 this.transactionInfo = nextTx;
@@ -223,7 +224,7 @@ namespace Apache.NMS.AMQP
                     // one to recover our state.
                     if (startNewTransaction && nextTx.ProviderTxId == null)
                     {
-                        await Begin();
+                        await Begin().Await();
                     }
                 }
                 catch (Exception e)
diff --git a/src/NMS.AMQP/NmsMessageConsumer.cs b/src/NMS.AMQP/NmsMessageConsumer.cs
index 36abe8f..d64632d 100644
--- a/src/NMS.AMQP/NmsMessageConsumer.cs
+++ b/src/NMS.AMQP/NmsMessageConsumer.cs
@@ -21,13 +21,14 @@ using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP
 {
     public class NmsMessageConsumer : IMessageConsumer
     {
-        private readonly object syncRoot = new object();
+        private readonly NmsSynchronizationMonitor syncRoot = new NmsSynchronizationMonitor();
         private readonly AcknowledgementMode acknowledgementMode;
         private readonly AtomicBool closed = new AtomicBool();
         private readonly MessageDeliveryTask deliveryTask;
@@ -64,13 +65,6 @@ namespace Apache.NMS.AMQP
 
             };
             deliveryTask = new MessageDeliveryTask(this);
-            
-            Session.Connection.CreateResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
-            
-            Session.Add(this);
-
-            if (Session.IsStarted)
-                Start();
         }
 
         public NmsSession Session { get; }
@@ -97,13 +91,18 @@ namespace Apache.NMS.AMQP
 
         public void Close()
         {
+            CloseAsync().GetAsyncResult();
+        }
+
+        public async Task CloseAsync()
+        {
             if (closed)
                 return;
 
-            lock (syncRoot)
+            using(await syncRoot.LockAsync().Await())
             {
                 Shutdown(null);
-                Session.Connection.DestroyResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
+                await Session.Connection.DestroyResource(Info).Await();
             }
         }
 
@@ -116,7 +115,7 @@ namespace Apache.NMS.AMQP
             add
             {
                 CheckClosed();
-                lock (syncRoot)
+                using(syncRoot.Lock())
                 {
                     Listener += value;
                     DrainMessageQueueToListener();
@@ -124,7 +123,7 @@ namespace Apache.NMS.AMQP
             }
             remove
             {
-                lock (syncRoot)
+                using(syncRoot.Lock())
                 {
                     Listener -= value;
                 }
@@ -140,13 +139,32 @@ namespace Apache.NMS.AMQP
             {
                 if (started)
                 {
-                    return ReceiveInternal(-1);
+                    return ReceiveInternalAsync(-1).GetAsyncResult();
                 }
             }
         }
-        
+
+        public async Task<IMessage> ReceiveAsync()
+        {
+            CheckClosed();
+            CheckMessageListener();
+
+            while (true)
+            {
+                if (started)
+                {
+                    return await ReceiveInternalAsync(-1).Await();
+                }
+            }
+        }
+
         public T ReceiveBody<T>()
         {
+            return ReceiveBodyAsync<T>().GetAsyncResult();
+        }
+        
+        public Task<T> ReceiveBodyAsync<T>()
+        {
             CheckClosed();
             CheckMessageListener();
 
@@ -154,7 +172,7 @@ namespace Apache.NMS.AMQP
             {
                 if (started)
                 {
-                    return ReceiveBodyInternal<T>(-1);
+                    return ReceiveBodyInternalAsync<T>(-1);
                 }
             }
         }
@@ -165,7 +183,7 @@ namespace Apache.NMS.AMQP
             CheckClosed();
             CheckMessageListener();
 
-            return started ? ReceiveInternal(0) : null;
+            return started ? ReceiveInternalAsync(0).GetAsyncResult() : null;
         }
         
         public T ReceiveBodyNoWait<T>()
@@ -173,19 +191,24 @@ namespace Apache.NMS.AMQP
             CheckClosed();
             CheckMessageListener();
 
-            return started ? ReceiveBodyInternal<T>(0) : default;
+            return started ? ReceiveBodyInternalAsync<T>(0).GetAsyncResult() : default;
         }
 
         public IMessage Receive(TimeSpan timeout)
         {
+            return ReceiveAsync(timeout).GetAsyncResult();
+        }
+        
+        public async Task<IMessage> ReceiveAsync(TimeSpan timeout)
+        {
             CheckClosed();
             CheckMessageListener();
-
+            
             int timeoutInMilliseconds = (int) timeout.TotalMilliseconds;
 
             if (started)
             {
-                return ReceiveInternal(timeoutInMilliseconds);
+                return await ReceiveInternalAsync(timeoutInMilliseconds).Await();
             }
 
             long deadline = GetDeadline(timeoutInMilliseconds);
@@ -200,13 +223,18 @@ namespace Apache.NMS.AMQP
 
                 if (started)
                 {
-                    return ReceiveInternal(timeoutInMilliseconds);
+                    return await ReceiveInternalAsync(timeoutInMilliseconds).Await();
                 }
             }
         }
         
         public T ReceiveBody<T>(TimeSpan timeout)
         {
+            return ReceiveBodyAsync<T>(timeout).GetAsyncResult();
+        }
+        
+        public async Task<T> ReceiveBodyAsync<T>(TimeSpan timeout)
+        {
             CheckClosed();
             CheckMessageListener();
 
@@ -214,7 +242,7 @@ namespace Apache.NMS.AMQP
 
             if (started)
             {
-                return ReceiveBodyInternal<T>(timeoutInMilliseconds);
+                return await ReceiveBodyInternalAsync<T>(timeoutInMilliseconds).Await();
             }
 
             long deadline = GetDeadline(timeoutInMilliseconds);
@@ -229,7 +257,7 @@ namespace Apache.NMS.AMQP
 
                 if (started)
                 {
-                    return ReceiveBodyInternal<T>(timeoutInMilliseconds);
+                    return await ReceiveBodyInternalAsync<T>(timeoutInMilliseconds).Await();
                 }
             }
         }
@@ -255,9 +283,16 @@ namespace Apache.NMS.AMQP
 
         private event MessageListener Listener;
 
-        public Task Init()
+        public async Task Init()
         {
-            return Session.Connection.StartResource(Info);
+            await Session.Connection.CreateResource(Info).Await();
+            
+            Session.Add(this);
+
+            if (Session.IsStarted)
+                Start();
+            
+            await Session.Connection.StartResource(Info).Await();
         }
 
         public void OnInboundMessage(InboundMessageDispatch envelope)
@@ -276,11 +311,14 @@ namespace Apache.NMS.AMQP
 
             if (Session.IsStarted && Listener != null)
             {
-                Session.EnqueueForDispatch(deliveryTask);
+                using (syncRoot.Exclude()) // Exclude lock for a time of dispatching, so it does not pass along to actionblock
+                {
+                    Session.EnqueueForDispatch(deliveryTask);
+                }
             }
         }
 
-        private void DeliverNextPending()
+        private async Task DeliverNextPendingAsync()
         {
             if (Tracer.IsDebugEnabled)
             {
@@ -289,7 +327,7 @@ namespace Apache.NMS.AMQP
             
             if (Session.IsStarted && started && Listener != null)
             {
-                lock (syncRoot)
+                using(await syncRoot.LockAsync())
                 {
                     try
                     {
@@ -313,7 +351,7 @@ namespace Apache.NMS.AMQP
                                     Tracer.Debug($"{Info.Id} filtered expired message: {envelope.Message.NMSMessageId}");
                                 }
 
-                                DoAckExpired(envelope);
+                                await DoAckExpiredAsync(envelope).Await();
                             }
                             else if (IsRedeliveryExceeded(envelope))
                             {
@@ -323,7 +361,7 @@ namespace Apache.NMS.AMQP
                                 }
 
                                 // TODO: Apply redelivery policy
-                                DoAckExpired(envelope);
+                                await DoAckExpiredAsync(envelope).Await();
                             }
                             else
                             {
@@ -331,9 +369,9 @@ namespace Apache.NMS.AMQP
                                 bool autoAckOrDupsOk = acknowledgementMode == AcknowledgementMode.AutoAcknowledge || acknowledgementMode == AcknowledgementMode.DupsOkAcknowledge;
 
                                 if (autoAckOrDupsOk)
-                                    DoAckDelivered(envelope);
+                                    await DoAckDeliveredAsync(envelope).Await();
                                 else
-                                    AckFromReceive(envelope);
+                                    await AckFromReceiveAsync(envelope).Await();
 
                                 try
                                 {
@@ -347,9 +385,9 @@ namespace Apache.NMS.AMQP
                                 if (autoAckOrDupsOk)
                                 {
                                     if (!deliveryFailed)
-                                        DoAckConsumed(envelope);
+                                        await DoAckConsumedAsync(envelope).Await();
                                     else
-                                        DoAckReleased(envelope);
+                                        await DoAckReleasedAsync(envelope).Await();
                                 }
                             }
                         }
@@ -386,29 +424,31 @@ namespace Apache.NMS.AMQP
             return false;
         }
 
-        private void DoAckReleased(InboundMessageDispatch envelope)
+        private Task DoAckReleasedAsync(InboundMessageDispatch envelope)
         {
-            Session.AcknowledgeIndividual(AckType.RELEASED, envelope);
+            return Session.AcknowledgeIndividualAsync(AckType.RELEASED, envelope);
         }
 
-        private IMessage ReceiveInternal(int timeout)
+        
+        private Task<IMessage> ReceiveInternalAsync(int timeout)
         {
-            return ReceiveInternal(timeout, envelope =>
+            return ReceiveInternalBaseAsync(timeout, async envelope =>
             {
                 IMessage message = envelope.Message.Copy();
-                AckFromReceive(envelope);
+                await AckFromReceiveAsync(envelope);
                 return message;
             });
         }
         
-        private T ReceiveBodyInternal<T>(int timeout)
+        
+        private Task<T> ReceiveBodyInternalAsync<T>(int timeout)
         {
-            return ReceiveInternal<T>(timeout, envelope =>
+            return ReceiveInternalBaseAsync<T>(timeout, async envelope =>
             {
                 try
                 {
                     T body = envelope.Message.Body<T>();
-                    AckFromReceive(envelope);
+                    await AckFromReceiveAsync(envelope);
                     return body;
                 }
                 catch (MessageFormatException mfe)
@@ -427,7 +467,7 @@ namespace Apache.NMS.AMQP
         }
 
 
-        private T ReceiveInternal<T>(int timeout, Func<InboundMessageDispatch, T> func)
+        private async Task<T> ReceiveInternalBaseAsync<T>(int timeout, Func<InboundMessageDispatch, Task<T>> func)
         {
             try
             {
@@ -444,7 +484,7 @@ namespace Apache.NMS.AMQP
                         Tracer.Debug("Trying to dequeue next message.");
                     }
 
-                    InboundMessageDispatch envelope = messageQueue.Dequeue(timeout);
+                    InboundMessageDispatch envelope = await messageQueue.DequeueAsync(timeout).Await();
 
                     if (failureCause != null)
                         throw NMSExceptionSupport.Create(failureCause);
@@ -459,7 +499,7 @@ namespace Apache.NMS.AMQP
                             Tracer.Debug($"{Info.Id} filtered expired message: {envelope.Message.NMSMessageId}");
                         }
 
-                        DoAckExpired(envelope);
+                        await DoAckExpiredAsync(envelope).Await();
 
                         if (timeout > 0)
                             timeout = (int) Math.Max(deadline - DateTime.UtcNow.Ticks / 10_000L, 0);
@@ -472,7 +512,7 @@ namespace Apache.NMS.AMQP
                         }
 
                         // TODO: Apply redelivery policy
-                        DoAckExpired(envelope);
+                        await DoAckExpiredAsync(envelope).Await();
                     }
                     else
                     {
@@ -481,7 +521,7 @@ namespace Apache.NMS.AMQP
                             Tracer.Debug($"{Info.Id} received message {envelope.Message.NMSMessageId}.");
                         }
 
-                        return func.Invoke(envelope);
+                        return await func.Invoke(envelope);
                     }
                 }
             }
@@ -501,35 +541,35 @@ namespace Apache.NMS.AMQP
             return DateTime.UtcNow.Ticks / 10_000L + timeout;
         }
 
-        private void AckFromReceive(InboundMessageDispatch envelope)
+        private async Task AckFromReceiveAsync(InboundMessageDispatch envelope)
         {
             if (envelope?.Message != null)
             {
                 NmsMessage message = envelope.Message;
                 if (message.NmsAcknowledgeCallback != null)
                 {
-                    DoAckDelivered(envelope);
+                    await DoAckDeliveredAsync(envelope).Await();
                 }
                 else
                 {
-                    DoAckConsumed(envelope);
+                    await DoAckConsumedAsync(envelope).Await();
                 }
             }
         }
 
-        private void DoAckDelivered(InboundMessageDispatch envelope)
+        private Task DoAckDeliveredAsync(InboundMessageDispatch envelope)
         {
-            Session.Acknowledge(AckType.DELIVERED, envelope);
+            return Session.AcknowledgeAsync(AckType.DELIVERED, envelope);
         }
 
-        private void DoAckConsumed(InboundMessageDispatch envelope)
+        private Task DoAckConsumedAsync(InboundMessageDispatch envelope)
         {
-            Session.Acknowledge(AckType.ACCEPTED, envelope);
+            return Session.AcknowledgeAsync(AckType.ACCEPTED, envelope);
         }
 
-        private void DoAckExpired(InboundMessageDispatch envelope)
+        private Task DoAckExpiredAsync(InboundMessageDispatch envelope)
         {
-            Session.Acknowledge(AckType.MODIFIED_FAILED_UNDELIVERABLE, envelope);
+            return Session.AcknowledgeAsync(AckType.MODIFIED_FAILED_UNDELIVERABLE, envelope);
         }
 
         private void SetAcknowledgeCallback(InboundMessageDispatch envelope)
@@ -587,7 +627,10 @@ namespace Apache.NMS.AMQP
                 int size = messageQueue.Count;
                 for (int i = 0; i < size; i++)
                 {
-                    Session.EnqueueForDispatch(deliveryTask);
+                    using (syncRoot.Exclude()) // Exclude lock for a time of dispatching, so it does not pass along to actionblock
+                    {
+                        Session.EnqueueForDispatch(deliveryTask);
+                    }
                 }
             }
         }
@@ -599,13 +642,13 @@ namespace Apache.NMS.AMQP
 
         public async Task OnConnectionRecovered(IProvider provider)
         {
-            await provider.StartResource(Info).ConfigureAwait(false);
+            await provider.StartResource(Info).Await();
             DrainMessageQueueToListener();
         }
 
         public void Stop()
         {
-            lock (syncRoot)
+            using(syncRoot.Lock())
             {
                 started.Set(false);
             }
@@ -621,13 +664,13 @@ namespace Apache.NMS.AMQP
             messageQueue.Clear();
         }
 
-        public void SuspendForRollback()
+        public async Task SuspendForRollbackAsync()
         {
             Stop();
 
             try
             {
-                Session.Connection.StopResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
+                await Session.Connection.StopResource(Info).Await();
             }
             finally
             {
@@ -638,17 +681,17 @@ namespace Apache.NMS.AMQP
             }
         }
 
-        public void ResumeAfterRollback()
+        public async Task ResumeAfterRollbackAsync()
         {
             Start();
-            StartConsumerResource();
+            await StartConsumerResourceAsync().Await();
         }
 
-        private void StartConsumerResource()
+        private async Task StartConsumerResourceAsync()
         {
             try
             {
-                Session.Connection.StartResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
+                await Session.Connection.StartResource(Info).Await();
             }
             catch (NMSException)
             {
@@ -666,9 +709,9 @@ namespace Apache.NMS.AMQP
                 this.consumer = consumer;
             }
 
-            public void DeliverNextPending()
+            public Task DeliverNextPending()
             {
-                consumer.DeliverNextPending();
+                return consumer.DeliverNextPendingAsync();
             }
         }
     }
diff --git a/src/NMS.AMQP/NmsMessageProducer.cs b/src/NMS.AMQP/NmsMessageProducer.cs
index 3f7e3db..e215861 100644
--- a/src/NMS.AMQP/NmsMessageProducer.cs
+++ b/src/NMS.AMQP/NmsMessageProducer.cs
@@ -21,6 +21,7 @@ using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
@@ -39,19 +40,22 @@ namespace Apache.NMS.AMQP
         private bool disableMessageId;
         private bool disableMessageTimestamp;
 
-        public NmsMessageProducer(NmsProducerId producerId, NmsSession session, IDestination destination)
+        internal NmsMessageProducer(NmsProducerId producerId, NmsSession session, IDestination destination)
         {
             this.session = session;
             Info = new NmsProducerInfo(producerId)
             {
                 Destination = destination
             };
+        }
 
-            session.Connection.CreateResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
+        internal async  Task Init()
+        {
+            await session.Connection.CreateResource(Info).Await();
 
             session.Add(this);
         }
-
+        
         public NmsProducerId ProducerId => Info.Id;
         public NmsProducerInfo Info { get; }
         public INmsMessageIdBuilder MessageIdBuilder { get; } = new DefaultMessageIdBuilder();
@@ -113,11 +117,16 @@ namespace Apache.NMS.AMQP
 
         public void Close()
         {
+            CloseAsync().GetAsyncResult();
+        }
+
+        public async Task CloseAsync()
+        {
             if (closed)
                 return;
 
             Shutdown();
-            session.Connection.DestroyResource(Info).ConfigureAwait(false).GetAwaiter().GetResult();
+            await session.Connection.DestroyResource(Info).Await();
         }
 
         public IMessage CreateMessage()
diff --git a/src/NMS.AMQP/NmsNoTxTransactionContext.cs b/src/NMS.AMQP/NmsNoTxTransactionContext.cs
index a8e1607..f9fc384 100644
--- a/src/NMS.AMQP/NmsNoTxTransactionContext.cs
+++ b/src/NMS.AMQP/NmsNoTxTransactionContext.cs
@@ -19,7 +19,6 @@ using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
-using Apache.NMS.AMQP.Util;
 
 namespace Apache.NMS.AMQP
 {
diff --git a/src/NMS.AMQP/NmsProducer.cs b/src/NMS.AMQP/NmsProducer.cs
index 974a185..fad1a2c 100644
--- a/src/NMS.AMQP/NmsProducer.cs
+++ b/src/NMS.AMQP/NmsProducer.cs
@@ -19,6 +19,7 @@ using System;
 using System.Collections;
 using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP
@@ -122,7 +123,7 @@ namespace Apache.NMS.AMQP
                 message.NMSReplyTo = replyTo;
             }
 
-            await producer.SendAsync(destination, message);
+            await producer.SendAsync(destination, message).Await();
             return this;
         }
 
@@ -200,6 +201,11 @@ namespace Apache.NMS.AMQP
             producer.Close();
         }
 
+        public Task CloseAsync()
+        {
+            return producer.CloseAsync();
+        }
+
 
         public string NMSCorrelationID
         {
diff --git a/src/NMS.AMQP/NmsQueueBrowser.cs b/src/NMS.AMQP/NmsQueueBrowser.cs
index e1eb348..4f39260 100644
--- a/src/NMS.AMQP/NmsQueueBrowser.cs
+++ b/src/NMS.AMQP/NmsQueueBrowser.cs
@@ -16,14 +16,16 @@
  */
 
 using System.Collections;
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
     public class NmsQueueBrowser : IQueueBrowser, IEnumerator
     {
-        private readonly object syncRoot = new object();
+        private readonly NmsSynchronizationMonitor syncRoot = new NmsSynchronizationMonitor();
 
         private readonly NmsSession session;
         private readonly IQueue destination;
@@ -103,8 +105,13 @@ namespace Apache.NMS.AMQP
 
         public void Close()
         {
+            CloseAsync().GetAsyncResult();
+        }
+
+        public async Task CloseAsync()
+        {
             if (closed.CompareAndSet(false, true)) {
-                DestroyConsumer();
+                await DestroyConsumerAsync().Await();
             }
         }
 
@@ -121,28 +128,33 @@ namespace Apache.NMS.AMQP
 
         private void CreateConsumer()
         {
-            lock (syncRoot)
+            using(syncRoot.Lock())
             {
                 if (consumer == null)
                 {
                     NmsMessageConsumer messageConsumer = new NmsQueueBrowserMessageConsumer(session.GetNextConsumerId(), session,
                         destination, selector, false);
 
-                    messageConsumer.Init().ConfigureAwait(false).GetAwaiter().GetResult();
+                    messageConsumer.Init().GetAsyncResult();
 
                     // Assign only after fully created and initialized.
                     consumer = messageConsumer;
                 }
             }
         }
-        
+
         private void DestroyConsumer()
         {
-            lock (syncRoot)
+            DestroyConsumerAsync().GetAsyncResult();
+        }
+        
+        private async Task DestroyConsumerAsync()
+        {
+            using(await syncRoot.LockAsync().Await())
             {
                 try
                 {
-                    consumer?.Close();
+                    await (consumer != null ? consumer.CloseAsync() : Task.CompletedTask).Await();
                 }
                 catch (NMSException e)
                 {
diff --git a/src/NMS.AMQP/NmsSession.cs b/src/NMS.AMQP/NmsSession.cs
index e1bb898..0eb697c 100644
--- a/src/NMS.AMQP/NmsSession.cs
+++ b/src/NMS.AMQP/NmsSession.cs
@@ -20,11 +20,11 @@ using System.Collections.Concurrent;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using Amqp;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
@@ -64,19 +64,19 @@ namespace Apache.NMS.AMQP
 
         internal async Task Begin()
         {
-            await Connection.CreateResource(SessionInfo).ConfigureAwait(false);
+            await Connection.CreateResource(SessionInfo).Await();
 
             try
             {
                 // We always keep an open TX if transacted so start now.
-                await TransactionContext.Begin().ConfigureAwait(false);
+                await TransactionContext.Begin().Await();
             }
             catch (Exception)
             {
                 // failed, close the AMQP session before we throw
                 try
                 {
-                    await Connection.DestroyResource(SessionInfo).ConfigureAwait(false);
+                    await Connection.DestroyResource(SessionInfo).Await();
                 }
                 catch (Exception)
                 {
@@ -88,12 +88,23 @@ namespace Apache.NMS.AMQP
 
         public void Close()
         {
-            CheckIsOnDeliveryThread();
+            CheckIsOnDeliveryExecutionFlow();
 
             if (!closed)
             {
                 Shutdown();
-                Connection.DestroyResource(SessionInfo);
+                Connection.DestroyResource(SessionInfo).GetAsyncResult();
+            }
+        }
+
+        public async Task CloseAsync()
+        {
+            CheckIsOnDeliveryExecutionFlow();
+
+            if (!closed)
+            {
+                await ShutdownAsync().Await();
+                await Connection.DestroyResource(SessionInfo).Await();
             }
         }
 
@@ -114,9 +125,21 @@ namespace Apache.NMS.AMQP
             return CreateProducer(null);
         }
 
+        public Task<IMessageProducer> CreateProducerAsync()
+        {
+            return CreateProducerAsync(null);
+        }
+
         public IMessageProducer CreateProducer(IDestination destination)
         {
-            return new NmsMessageProducer(GetNextProducerId(), this, destination);
+            return CreateProducerAsync(destination).GetAsyncResult();
+        }
+
+        public async Task<IMessageProducer> CreateProducerAsync(IDestination destination)
+        {
+            var producer = new NmsMessageProducer(GetNextProducerId(), this, destination);
+            await producer.Init().Await();
+            return producer;
         }
         
         private NmsProducerId GetNextProducerId()
@@ -129,18 +152,33 @@ namespace Apache.NMS.AMQP
             return CreateConsumer(destination, null);
         }
 
+        public Task<IMessageConsumer> CreateConsumerAsync(IDestination destination)
+        {
+            return CreateConsumerAsync(destination, null);
+        }
+
         public IMessageConsumer CreateConsumer(IDestination destination, string selector)
         {
             return CreateConsumer(destination, selector, false);
         }
 
+        public Task<IMessageConsumer> CreateConsumerAsync(IDestination destination, string selector)
+        {
+            return CreateConsumerAsync(destination, selector, false);
+        }
+
         public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal)
         {
+            return CreateConsumerAsync(destination, selector, noLocal).GetAsyncResult();
+        }
+
+        public async Task<IMessageConsumer> CreateConsumerAsync(IDestination destination, string selector, bool noLocal)
+        {
             CheckClosed();
 
             NmsMessageConsumer messageConsumer = new NmsMessageConsumer(GetNextConsumerId(), this, destination, selector, noLocal);
-            messageConsumer.Init().ConfigureAwait(false).GetAwaiter().GetResult();
-            
+            await messageConsumer.Init().Await();
+
             return messageConsumer;
         }
 
@@ -149,17 +187,32 @@ namespace Apache.NMS.AMQP
             return CreateDurableConsumer(destination, name, null, false);
         }
 
+        public Task<IMessageConsumer> CreateDurableConsumerAsync(ITopic destination, string name)
+        {
+            return CreateDurableConsumerAsync(destination, name, null, false);
+        }
+
         public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector)
         {
             return CreateDurableConsumer(destination, name, selector, false);
         }
 
+        public Task<IMessageConsumer> CreateDurableConsumerAsync(ITopic destination, string name, string selector)
+        {
+            return CreateDurableConsumerAsync(destination, name, selector, false);
+        }
+
         public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector, bool noLocal)
         {
+            return CreateDurableConsumerAsync(destination, name, selector, noLocal).GetAsyncResult();
+        }
+
+        public async Task<IMessageConsumer> CreateDurableConsumerAsync(ITopic destination, string name, string selector, bool noLocal)
+        {
             CheckClosed();
 
             NmsMessageConsumer messageConsumer = new NmsDurableMessageConsumer(GetNextConsumerId(), this, destination, name, selector, noLocal);
-            messageConsumer.Init().ConfigureAwait(false).GetAwaiter().GetResult();
+            await messageConsumer.Init().Await();
 
             return messageConsumer;
         }
@@ -169,12 +222,22 @@ namespace Apache.NMS.AMQP
             return CreateSharedConsumer(destination, name, null);
         }
 
+        public Task<IMessageConsumer> CreateSharedConsumerAsync(ITopic destination, string name)
+        {
+            return CreateSharedConsumerAsync(destination, name, null);
+        }
+
         public IMessageConsumer CreateSharedConsumer(ITopic destination, string name, string selector)
         {
+            return CreateSharedConsumerAsync(destination, name, selector).GetAsyncResult();
+        }
+
+        public async Task<IMessageConsumer> CreateSharedConsumerAsync(ITopic destination, string name, string selector)
+        {
             CheckClosed();
 
             NmsMessageConsumer messageConsumer = new NmsSharedMessageConsumer(GetNextConsumerId(), this, destination, name, selector, false);
-            messageConsumer.Init().ConfigureAwait(false).GetAwaiter().GetResult();
+            await messageConsumer.Init().Await();
             
             return messageConsumer;
         }
@@ -184,12 +247,22 @@ namespace Apache.NMS.AMQP
             return CreateSharedDurableConsumer(destination, name, null);
         }
 
+        public Task<IMessageConsumer> CreateSharedDurableConsumerAsync(ITopic destination, string name)
+        {
+            return CreateSharedDurableConsumerAsync(destination, name, null);
+        }
+
         public IMessageConsumer CreateSharedDurableConsumer(ITopic destination, string name, string selector)
         {
+            return CreateSharedDurableConsumerAsync(destination, name, selector).GetAsyncResult();
+        }
+
+        public async Task<IMessageConsumer> CreateSharedDurableConsumerAsync(ITopic destination, string name, string selector)
+        {
             CheckClosed();
 
             NmsMessageConsumer messageConsumer = new NmsSharedDurableMessageConsumer(GetNextConsumerId(), this, destination, name, selector, false);
-            messageConsumer.Init().ConfigureAwait(false).GetAwaiter().GetResult();
+            await messageConsumer.Init().Await();//.GetAwaiter().GetResult();
             
             return messageConsumer;
         }
@@ -206,16 +279,32 @@ namespace Apache.NMS.AMQP
 
         public void Unsubscribe(string name)
         {
+            UnsubscribeAsync(name).GetAsyncResult();
+        }
+
+        public async Task UnsubscribeAsync(string name)
+        {
             CheckClosed();
 
-            Connection.Unsubscribe(name);
+            await Connection.UnsubscribeAsync(name).Await();
         }
 
+        public Task<IQueueBrowser> CreateBrowserAsync(IQueue queue)
+        {
+            return Task.FromResult(CreateBrowser(queue));
+        }
+       
+        public Task<IQueueBrowser> CreateBrowserAsync(IQueue queue, string selector)
+        {
+            return Task.FromResult(CreateBrowser(queue, selector));
+        }
+        
         public IQueueBrowser CreateBrowser(IQueue queue)
         {
             return CreateBrowser(queue, null);
         }
 
+       
         public IQueueBrowser CreateBrowser(IQueue queue, string selector)
         {
             CheckClosed();
@@ -230,6 +319,11 @@ namespace Apache.NMS.AMQP
             return new NmsQueue(name);
         }
 
+        public Task<IQueue> GetQueueAsync(string name)
+        {
+            return Task.FromResult(GetQueue(name));
+        }
+
         public ITopic GetTopic(string name)
         {
             CheckClosed();
@@ -237,31 +331,51 @@ namespace Apache.NMS.AMQP
             return new NmsTopic(name);
         }
 
+        public Task<ITopic> GetTopicAsync(string name)
+        {
+            return Task.FromResult(GetTopic(name));
+        }
+
         public ITemporaryQueue CreateTemporaryQueue()
         {
+            return CreateTemporaryQueueAsync().GetAsyncResult();
+        }
+
+        public async Task<ITemporaryQueue> CreateTemporaryQueueAsync()
+        {
             CheckClosed();
 
-            return Connection.CreateTemporaryQueue();
+            return await Connection.CreateTemporaryQueueAsync().Await();
         }
 
         public ITemporaryTopic CreateTemporaryTopic()
         {
+            return CreateTemporaryTopicAsync().GetAsyncResult();
+        }
+
+        public async Task<ITemporaryTopic> CreateTemporaryTopicAsync()
+        {
             CheckClosed();
 
-            return Connection.CreateTemporaryTopic();
+            return await Connection.CreateTemporaryTopicAsync().Await();
         }
 
         public void DeleteDestination(IDestination destination)
         {
+            DeleteDestinationAsync(destination).GetAsyncResult();
+        }
+
+        public async Task DeleteDestinationAsync(IDestination destination)
+        {
             CheckClosed();
 
             if (destination == null)
                 return;
 
             if (destination is ITemporaryQueue temporaryQueue)
-                temporaryQueue.Delete();
+                await temporaryQueue.DeleteAsync().Await();
             else if (destination is ITemporaryTopic temporaryTopic)
-                temporaryTopic.Delete();
+                await temporaryTopic.DeleteAsync().Await();
             else
                 throw new NotSupportedException("AMQP can not delete a Queue or Topic destination.");
         }
@@ -273,6 +387,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateMessage();
         }
 
+        public Task<IMessage> CreateMessageAsync()
+        {
+            return Task.FromResult(CreateMessage());
+        }
+
         public ITextMessage CreateTextMessage()
         {
             CheckClosed();
@@ -280,6 +399,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateTextMessage();
         }
 
+        public Task<ITextMessage> CreateTextMessageAsync()
+        {
+            return Task.FromResult(CreateTextMessage());
+        }
+
         public ITextMessage CreateTextMessage(string text)
         {
             CheckClosed();
@@ -287,6 +411,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateTextMessage(text);
         }
 
+        public Task<ITextMessage> CreateTextMessageAsync(string text)
+        {
+            return Task.FromResult(CreateTextMessage(text));
+        }
+
         public IMapMessage CreateMapMessage()
         {
             CheckClosed();
@@ -294,6 +423,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateMapMessage();
         }
 
+        public Task<IMapMessage> CreateMapMessageAsync()
+        {
+            return Task.FromResult(CreateMapMessage());
+        }
+
         public IObjectMessage CreateObjectMessage(object body)
         {
             CheckClosed();
@@ -301,6 +435,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateObjectMessage(body);
         }
 
+        public Task<IObjectMessage> CreateObjectMessageAsync(object body)
+        {
+            return Task.FromResult(CreateObjectMessage(body));
+        }
+
         public IBytesMessage CreateBytesMessage()
         {
             CheckClosed();
@@ -308,6 +447,11 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateBytesMessage();
         }
 
+        public Task<IBytesMessage> CreateBytesMessageAsync()
+        {
+            return Task.FromResult(CreateBytesMessage());
+        }
+
         public IBytesMessage CreateBytesMessage(byte[] body)
         {
             CheckClosed();
@@ -315,21 +459,36 @@ namespace Apache.NMS.AMQP
             return Connection.MessageFactory.CreateBytesMessage(body);
         }
 
+        public Task<IBytesMessage> CreateBytesMessageAsync(byte[] body)
+        {
+            return Task.FromResult(CreateBytesMessage(body));
+        }
+
         public IStreamMessage CreateStreamMessage()
         {
             CheckClosed();
 
             return Connection.MessageFactory.CreateStreamMessage();
         }
+        
+        public Task<IStreamMessage> CreateStreamMessageAsync()
+        {
+            return Task.FromResult(CreateStreamMessage());
+        }
 
         public void Recover()
         {
+            RecoverAsync().GetAsyncResult();
+        }
+
+        public async Task RecoverAsync()
+        {
             CheckClosed();
 
             bool wasStarted = IsStarted;
             Stop();
             
-            Connection.Recover(SessionInfo.Id).ConfigureAwait(false).GetAwaiter().GetResult();
+            await Connection.Recover(SessionInfo.Id).Await();
 
             if (wasStarted) 
                 Start();
@@ -337,8 +496,13 @@ namespace Apache.NMS.AMQP
 
         public void Acknowledge()
         {
+            AcknowledgeAsync().GetAsyncResult();
+        }
+        
+        public async Task AcknowledgeAsync()
+        {
             if (acknowledgementMode == AcknowledgementMode.ClientAcknowledge) {
-                Acknowledge(AckType.ACCEPTED);
+                await AcknowledgeAsync(AckType.ACCEPTED).Await();
             }
         }
 
@@ -346,11 +510,23 @@ namespace Apache.NMS.AMQP
         {
             CheckClosed();
 
-            TransactionContext.Commit().ConfigureAwait(false).GetAwaiter().GetResult();
+            TransactionContext.Commit().GetAsyncResult();
+        }
+
+        public async Task CommitAsync()
+        {
+            CheckClosed();
+
+            await TransactionContext.Commit().Await();
         }
 
         public void Rollback()
         {
+            RollbackAsync().GetAsyncResult();
+        }
+
+        public async Task RollbackAsync()
+        {
             CheckClosed();
             
             // Stop processing any new messages that arrive
@@ -358,19 +534,19 @@ namespace Apache.NMS.AMQP
             {
                 foreach (NmsMessageConsumer consumer in consumers.Values)
                 {
-                    consumer.SuspendForRollback();
+                    await consumer.SuspendForRollbackAsync().Await();
                 }
             }
             finally
             {
-                TransactionContext.Rollback().ConfigureAwait(false).GetAwaiter().GetResult();    
+                await TransactionContext.Rollback().Await(); //.GetAsyncResult();    
             }
             
             // Currently some consumers won't get suspended and some won't restart
             // after a failed rollback.
             foreach (NmsMessageConsumer consumer in consumers.Values)
             {
-                consumer.ResumeAfterRollback();
+                await consumer.ResumeAfterRollbackAsync().Await();
             }
         }
 
@@ -430,24 +606,24 @@ namespace Apache.NMS.AMQP
             }
         }
 
-        public void Acknowledge(AckType ackType)
+        public Task AcknowledgeAsync(AckType ackType)
         {
-            Connection.Acknowledge(SessionInfo.Id, ackType).ConfigureAwait(false).GetAwaiter().GetResult();
+            return Connection.Acknowledge(SessionInfo.Id, ackType);
         }
 
-        public void Acknowledge(AckType ackType, InboundMessageDispatch envelope)
+        public Task AcknowledgeAsync(AckType ackType, InboundMessageDispatch envelope)
         {
-            TransactionContext.Acknowledge(envelope, ackType).ConfigureAwait(false).GetAwaiter().GetResult();
+            return TransactionContext.Acknowledge(envelope, ackType);
         }
 
-        public void AcknowledgeIndividual(AckType ackType, InboundMessageDispatch envelope)
+        public Task AcknowledgeIndividualAsync(AckType ackType, InboundMessageDispatch envelope)
         {
             if (Transacted)
             {
                 throw new IllegalStateException("Message acknowledge called inside a transacted Session");
             }
 
-            Connection.Acknowledge(envelope, ackType).ConfigureAwait(false).GetAwaiter().GetResult();
+            return Connection.Acknowledge(envelope, ackType); //.GetAsyncResult();
         }
 
         public void Send(NmsMessageProducer producer, IDestination destination, IMessage original,
@@ -456,7 +632,7 @@ namespace Apache.NMS.AMQP
         {
 
             SendAsync(producer, destination, original, deliveryMode, priority, timeToLive, disableMessageId,
-                disableMessageTimestamp, deliveryDelay).ConfigureAwait(false).GetAwaiter().GetResult();
+                disableMessageTimestamp, deliveryDelay).GetAsyncResult();
             
         }
 
@@ -617,6 +793,11 @@ namespace Apache.NMS.AMQP
 
         public void Shutdown(NMSException exception = null)
         {
+            ShutdownAsync(exception).GetAsyncResult();
+        }
+
+        public async Task ShutdownAsync(NMSException exception = null)
+        {
             if (closed.CompareAndSet(false, true))
             {
                 failureCause = exception;
@@ -630,7 +811,7 @@ namespace Apache.NMS.AMQP
                     foreach (NmsMessageProducer producer in producers.Values.ToArray()) 
                         producer.Shutdown(exception);
 
-                    TransactionContext.Shutdown().ConfigureAwait(false).GetAwaiter().GetResult();
+                    await TransactionContext.Shutdown().Await();
                 }
                 finally
                 {
@@ -638,7 +819,7 @@ namespace Apache.NMS.AMQP
                 }
             }
         }
-
+        
         public void Start()
         {
             if (started.CompareAndSet(false, true))
@@ -652,9 +833,9 @@ namespace Apache.NMS.AMQP
             }
         }
 
-        internal void CheckIsOnDeliveryThread()
+        internal void CheckIsOnDeliveryExecutionFlow()
         {
-            if (dispatcher != null && dispatcher.IsOnDeliveryThread())
+            if (dispatcher != null && dispatcher.IsOnDeliveryExecutionFlow())
             {
                 throw new IllegalStateException("Illegal invocation from MessageListener callback");
             }
@@ -662,16 +843,16 @@ namespace Apache.NMS.AMQP
 
         public async Task OnConnectionRecovery(IProvider provider)
         {
-            await provider.CreateResource(SessionInfo).ConfigureAwait(false);
+            await provider.CreateResource(SessionInfo).Await();
 
             foreach (NmsMessageConsumer consumer in consumers.Values)
             {
-                await consumer.OnConnectionRecovery(provider).ConfigureAwait(false);
+                await consumer.OnConnectionRecovery(provider).Await();
             }
 
             foreach (NmsMessageProducer producer in producers.Values)
             {
-                await producer.OnConnectionRecovery(provider).ConfigureAwait(false);
+                await producer.OnConnectionRecovery(provider).Await();
             }
         }
 
@@ -679,7 +860,7 @@ namespace Apache.NMS.AMQP
         {
             foreach (NmsMessageConsumer consumer in consumers.Values)
             {
-                await consumer.OnConnectionRecovered(provider).ConfigureAwait(false);
+                await consumer.OnConnectionRecovered(provider).Await();
             }
         }
 
diff --git a/src/NMS.AMQP/NmsTemporaryDestination.cs b/src/NMS.AMQP/NmsTemporaryDestination.cs
index a2876d4..1f1d092 100644
--- a/src/NMS.AMQP/NmsTemporaryDestination.cs
+++ b/src/NMS.AMQP/NmsTemporaryDestination.cs
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Meta;
-using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
@@ -36,9 +37,14 @@ namespace Apache.NMS.AMQP
         
         public void Dispose()
         {
+            DeleteAsync().GetAsyncResult();
+        }
+
+        public async Task DeleteAsync()
+        {
             if (Connection != null)
             {
-                Connection.DeleteTemporaryDestination(this);
+                await Connection.DeleteTemporaryDestinationAsync(this).Await();
                 Connection = null;
             }
         }
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpConnection.cs b/src/NMS.AMQP/Provider/Amqp/AmqpConnection.cs
index 6b40430..0e30ad6 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpConnection.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpConnection.cs
@@ -27,6 +27,7 @@ using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider.Amqp.Message;
 using Apache.NMS.AMQP.Transport;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -73,11 +74,11 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         {
             Address address = UriUtil.ToAddress(remoteUri, Info.UserName, Info.Password);
             this.tsc = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
-            underlyingConnection = await transport.CreateAsync(address, new AmqpHandler(this)).ConfigureAwait(false);
+            underlyingConnection = await transport.CreateAsync(address, new AmqpHandler(this)).AwaitRunContinuationAsync();
             underlyingConnection.AddClosedCallback(OnClosed);
 
             // Wait for connection to be opened
-            await this.tsc.Task.ConfigureAwait(false);
+            await this.tsc.Task.Await();
 
             // Create a Session for this connection that is used for Temporary Destinations
             // and perhaps later on management and advisory monitoring.
@@ -85,7 +86,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             sessionInfo.AcknowledgementMode = AcknowledgementMode.AutoAcknowledge;
 
             connectionSession = new AmqpConnectionSession(this, sessionInfo);
-            await connectionSession.Start().ConfigureAwait(false);
+            await connectionSession.Start().Await();
         }
 
         private void OnClosed(IAmqpObject sender, Error error)
@@ -174,7 +175,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         public async Task CreateSession(NmsSessionInfo sessionInfo)
         {
             var amqpSession = new AmqpSession(this, sessionInfo);
-            await amqpSession.Start().ConfigureAwait(false);
+            await amqpSession.Start().Await();
             sessions.TryAdd(sessionInfo.Id, amqpSession);
         }
 
@@ -192,6 +193,20 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             }
         }
 
+        public async Task CloseAsync()
+        {
+            try
+            {
+                if (UnderlyingConnection != null) await UnderlyingConnection.CloseAsync().AwaitRunContinuationAsync();
+            }
+            catch (Exception ex)
+            {
+                // log network errors
+                NMSException nmse = ExceptionSupport.Wrap(ex, "Amqp Connection close failure for NMS Connection {0}", this.Info.Id);
+                Tracer.DebugFormat("Caught Exception while closing Amqp Connection {0}. Exception {1}", this.Info.Id, nmse);
+            }
+        }
+
         public AmqpSession GetSession(NmsSessionId sessionId)
         {
             if (sessions.TryGetValue(sessionId, out AmqpSession session))
@@ -209,7 +224,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         public async Task CreateTemporaryDestination(NmsTemporaryDestination destination)
         {
             AmqpTemporaryDestination amqpTemporaryDestination = new AmqpTemporaryDestination(connectionSession, destination);
-            await amqpTemporaryDestination.Attach();
+            await amqpTemporaryDestination.Attach().Await();
             temporaryDestinations.TryAdd(destination, amqpTemporaryDestination);
         }
 
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpConnectionSession.cs b/src/NMS.AMQP/Provider/Amqp/AmqpConnectionSession.cs
index c89133a..ba9399e 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpConnectionSession.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpConnectionSession.cs
@@ -22,6 +22,7 @@ using Amqp.Framing;
 using Amqp.Types;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -57,9 +58,9 @@ namespace Apache.NMS.AMQP.Provider.Amqp
                 tcs.TrySetException(exception);
             });
 
-            await tcs.Task;
+            await tcs.Task.Await();
             
-            receiverLink.Close(TimeSpan.FromMilliseconds(Connection.Provider.CloseTimeout));
+            await receiverLink.CloseAsync(TimeSpan.FromMilliseconds(Connection.Provider.CloseTimeout)).AwaitRunContinuationAsync();
         }
 
         private Attach CreateAttach(string subscriptionName)
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpConsumer.cs b/src/NMS.AMQP/Provider/Amqp/AmqpConsumer.cs
index d4ceeac..fc3a5cf 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpConsumer.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpConsumer.cs
@@ -27,6 +27,7 @@ using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider.Amqp.Filters;
 using Apache.NMS.AMQP.Provider.Amqp.Message;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -391,15 +392,15 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             }
         }
 
-        public void Close()
+        public async Task CloseAsync()
         {
             if (info.IsDurable)
             {
-                receiverLink?.Detach();
+                if (receiverLink != null) await receiverLink.DetachAsync().AwaitRunContinuationAsync();
             }
             else
             {
-                receiverLink?.Close();
+                if (receiverLink != null) await receiverLink.CloseAsync().AwaitRunContinuationAsync();
             }
         }
 
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpProducer.cs b/src/NMS.AMQP/Provider/Amqp/AmqpProducer.cs
index d52a278..5da3e31 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpProducer.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpProducer.cs
@@ -24,6 +24,7 @@ using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Provider.Amqp.Message;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -55,7 +56,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             };
 
             string linkName = info.Id + ":" + target.Address;
-            var taskCompletionSource = new TaskCompletionSource<bool>();
+            var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
             senderLink = new SenderLink(session.UnderlyingSession, linkName, frame, HandleOpened(taskCompletionSource));
 
             senderLink.AddClosedCallback((sender, error) =>
@@ -75,7 +76,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
 
             return taskCompletionSource.Task;
         }
-        
+
         private OnAttached HandleOpened(TaskCompletionSource<bool> tsc) => (link, attach) =>
         {
             if (IsClosePending(attach))
@@ -141,7 +142,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
                         SendSync(message, transactionalState);
                         return;
                     }
-                    await SendAsync(message, transactionalState).ConfigureAwait(false);
+                    await SendAsync(message, transactionalState).Await();
                 }
                 catch (AmqpException amqpEx)
                 {
@@ -178,7 +179,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             try
             {
                 senderLink.Send(message, deliveryState, _onOutcome, tcs);
-                await tcs.Task.ConfigureAwait(false);
+                await tcs.Task.Await();
             }
             finally
             {
@@ -210,12 +211,12 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             }
         }
 
-        public void Close()
+        public async Task CloseAsync()
         {
             try
             {
                 var closeTimeout = session.Connection.Provider.CloseTimeout;
-                senderLink.Close(TimeSpan.FromMilliseconds(closeTimeout));
+                await senderLink.CloseAsync(TimeSpan.FromMilliseconds(closeTimeout)).AwaitRunContinuationAsync();
             }
             catch (NMSException)
             {
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpProvider.cs b/src/NMS.AMQP/Provider/Amqp/AmqpProvider.cs
index c31bdeb..0720820 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpProvider.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpProvider.cs
@@ -18,11 +18,10 @@
 using System;
 using System.Threading.Tasks;
 using Amqp;
-using Amqp.Framing;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Transport;
-using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -135,6 +134,11 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             connection?.Close();
         }
 
+        public Task CloseAsync()
+        {
+            return connection?.CloseAsync();
+        }
+        
         public void SetProviderListener(IProviderListener providerListener)
         {
             Listener = providerListener;
@@ -166,49 +170,49 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             }
         }
 
-        public Task DestroyResource(INmsResource resourceInfo)
+        public async Task DestroyResource(INmsResource resourceInfo)
         {
             switch (resourceInfo)
             {
                 case NmsSessionInfo sessionInfo:
                 {
                     AmqpSession session = connection.GetSession(sessionInfo.Id);
-                    session.Close();
-                    return Task.CompletedTask;
+                    await session.CloseAsync().Await();
+                    return;
                 }
                 case NmsConsumerInfo consumerInfo:
                 {
                     AmqpSession session = connection.GetSession(consumerInfo.SessionId);
                     AmqpConsumer consumer = session.GetConsumer(consumerInfo.Id);
-                    consumer.Close();
+                    await consumer.CloseAsync().Await();;
                     session.RemoveConsumer(consumerInfo.Id);
-                    return Task.CompletedTask;
+                    return;
                 }
                 case NmsProducerInfo producerInfo:
                 {
                     AmqpSession session = connection.GetSession(producerInfo.SessionId);
                     AmqpProducer producer = session.GetProducer(producerInfo.Id);
-                    producer.Close();
+                    await producer.CloseAsync().Await();;
                     session.RemoveProducer(producerInfo.Id);
-                    return Task.CompletedTask;
+                    return;
                 }
                 case NmsTemporaryDestination temporaryDestination:
                 {
                     AmqpTemporaryDestination amqpTemporaryDestination = connection.GetTemporaryDestination(temporaryDestination);
                     if (amqpTemporaryDestination != null)
                     {
-                        amqpTemporaryDestination.Close();
+                        await amqpTemporaryDestination.CloseAsync().Await();;
                         connection.RemoveTemporaryDestination(temporaryDestination);
                     }
                     else
                         Tracer.Debug($"Could not find temporary destination {temporaryDestination} to delete.");
 
-                    return Task.CompletedTask;
+                    return;
                 }
                 default:
                     throw new ArgumentOutOfRangeException(nameof(resourceInfo), "Not supported resource type.");
             }
-        }
+          }
 
         public Task StartResource(INmsResource resourceInfo)
         {
@@ -270,7 +274,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         {
             AmqpSession session = connection.GetSession(envelope.ProducerInfo.SessionId);
             AmqpProducer producer = session.GetProducer(envelope.ProducerId);
-            await producer.Send(envelope).ConfigureAwait(false);
+            await producer.Send(envelope).Await();
             envelope.Message.IsReadOnly = false;
         }
 
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpSendTask.cs b/src/NMS.AMQP/Provider/Amqp/AmqpSendTask.cs
index d53c0fc..5676780 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpSendTask.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpSendTask.cs
@@ -29,7 +29,8 @@ namespace Apache.NMS.AMQP.Provider.Amqp
     {
         private readonly Timer timer;
         
-        public AmqpSendTask(SenderLink link, global::Amqp.Message message, DeliveryState deliveryState, long timeoutMillis)
+        public AmqpSendTask(SenderLink link, global::Amqp.Message message, DeliveryState deliveryState, long timeoutMillis) 
+            : base(TaskCreationOptions.RunContinuationsAsynchronously)
         {
             if (timeoutMillis != NmsConnectionInfo.INFINITE)
             {
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpSession.cs b/src/NMS.AMQP/Provider/Amqp/AmqpSession.cs
index d2c5c81..2be170c 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpSession.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpSession.cs
@@ -25,6 +25,7 @@ using Amqp;
 using Amqp.Framing;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -83,14 +84,14 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             return tcs.Task;
         }
 
-        public void Close()
+        public async Task CloseAsync()
         {
             long closeTimeout = Connection.Provider.CloseTimeout;
             TimeSpan timeout = TimeSpan.FromMilliseconds(closeTimeout);
-            UnderlyingSession.Close(timeout);
+            await UnderlyingSession.CloseAsync(timeout).AwaitRunContinuationAsync();
             Connection.RemoveSession(SessionInfo.Id);
         }
-
+        
         public Task BeginTransaction(NmsTransactionInfo transactionInfo)
         {
             if (!SessionInfo.IsTransacted)
@@ -115,14 +116,14 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         public async Task CreateConsumer(NmsConsumerInfo consumerInfo)
         {
             AmqpConsumer amqpConsumer = new AmqpConsumer(this, consumerInfo);
-            await amqpConsumer.Attach();
+            await amqpConsumer.Attach().Await();;
             consumers.TryAdd(consumerInfo.Id, amqpConsumer);
         }
 
         public async Task CreateProducer(NmsProducerInfo producerInfo)
         {
             var amqpProducer = new AmqpProducer(this, producerInfo);
-            await amqpProducer.Attach();
+            await amqpProducer.Attach().Await();;
             producers.TryAdd(producerInfo.Id, amqpProducer);
         }
 
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpTemporaryDestination.cs b/src/NMS.AMQP/Provider/Amqp/AmqpTemporaryDestination.cs
index 6a76632..263e117 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpTemporaryDestination.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpTemporaryDestination.cs
@@ -21,6 +21,7 @@ using Amqp;
 using Amqp.Framing;
 using Amqp.Types;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -94,12 +95,12 @@ namespace Apache.NMS.AMQP.Provider.Amqp
 
             return result;
         }
-
-        public void Close()
+        
+        public async Task CloseAsync()
         {
             try
             {
-                senderLink.Close();
+                await senderLink.CloseAsync().AwaitRunContinuationAsync();
             }
             catch (NMSException)
             {
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpTransactionContext.cs b/src/NMS.AMQP/Provider/Amqp/AmqpTransactionContext.cs
index 0a77f4a..2e46699 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpTransactionContext.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpTransactionContext.cs
@@ -21,7 +21,7 @@ using System.Threading.Tasks;
 using Amqp.Framing;
 using Amqp.Transactions;
 using Apache.NMS.AMQP.Meta;
-using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -66,14 +66,14 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             Tracer.Debug($"TX Context{this} rolling back current TX[{this.current}]");
 
             this.current = null;
-            await this.coordinator.DischargeAsync(this.txnId, true).ConfigureAwait(false);
+            await this.coordinator.DischargeAsync(this.txnId, true).Await();
             
 
             PostRollback();
 
             if (nextTransactionInfo != null)
             {
-                await Begin(nextTransactionInfo).ConfigureAwait(false);
+                await Begin(nextTransactionInfo).Await();
             }
         }
 
@@ -101,11 +101,11 @@ namespace Apache.NMS.AMQP.Provider.Amqp
             Tracer.Debug($"TX Context{this} committing back current TX[{this.current}]");
 
             this.current = null;
-            await this.coordinator.DischargeAsync(this.txnId, false).ConfigureAwait(false);
+            await this.coordinator.DischargeAsync(this.txnId, false).Await();
 
             PostCommit();
 
-            await Begin(nextTransactionInfo).ConfigureAwait(false);
+            await Begin(nextTransactionInfo).Await();
         }
 
         private void PostCommit()
@@ -123,7 +123,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
                 this.coordinator = new AmqpTransactionCoordinator(this.session);
             }
 
-            this.txnId = await this.coordinator.DeclareAsync().ConfigureAwait(false);
+            this.txnId = await this.coordinator.DeclareAsync().Await();
             this.current = transactionInfo.Id;
             transactionInfo.ProviderTxId = this.txnId;
             this.cachedTransactedState = new TransactionalState { TxnId = this.txnId };
diff --git a/src/NMS.AMQP/Provider/Amqp/AmqpTransactionCoordinator.cs b/src/NMS.AMQP/Provider/Amqp/AmqpTransactionCoordinator.cs
index 3fab595..0281b5c 100644
--- a/src/NMS.AMQP/Provider/Amqp/AmqpTransactionCoordinator.cs
+++ b/src/NMS.AMQP/Provider/Amqp/AmqpTransactionCoordinator.cs
@@ -21,6 +21,7 @@ using Amqp;
 using Amqp.Framing;
 using Amqp.Transactions;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Amqp
 {
@@ -51,7 +52,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
 
         public async Task<byte[]> DeclareAsync()
         {
-            var outcome = await this.SendAsync(DeclareMessage, null, this.session.Connection.Provider.RequestTimeout).ConfigureAwait(false);
+            var outcome = await this.SendAsync(DeclareMessage, null, this.session.Connection.Provider.RequestTimeout).Await();
             if (outcome.Descriptor.Code == MessageSupport.DECLARED_INSTANCE.Descriptor.Code)
             {
                 return ((Declared) outcome).TxnId;
@@ -71,7 +72,7 @@ namespace Apache.NMS.AMQP.Provider.Amqp
         public async Task DischargeAsync(byte[] txnId, bool fail)
         {
             var message = new global::Amqp.Message(new Discharge { TxnId = txnId, Fail = fail });
-            var outcome = await this.SendAsync(message, null, this.session.Connection.Provider.RequestTimeout).ConfigureAwait(false);
+            var outcome = await this.SendAsync(message, null, this.session.Connection.Provider.RequestTimeout).Await();
 
             if (outcome.Descriptor.Code == MessageSupport.ACCEPTED_INSTANCE.Descriptor.Code)
             {
diff --git a/src/NMS.AMQP/Provider/Failover/FailoverProvider.cs b/src/NMS.AMQP/Provider/Failover/FailoverProvider.cs
index c567687..80d4b89 100644
--- a/src/NMS.AMQP/Provider/Failover/FailoverProvider.cs
+++ b/src/NMS.AMQP/Provider/Failover/FailoverProvider.cs
@@ -22,6 +22,7 @@ using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Meta;
 using Apache.NMS.AMQP.Util;
+using Apache.NMS.AMQP.Util.Synchronization;
 using Apache.NMS.Util;
 
 namespace Apache.NMS.AMQP.Provider.Failover
@@ -128,8 +129,8 @@ namespace Apache.NMS.AMQP.Provider.Failover
                             {
                                 Tracer.Debug($"Connection attempt:[{reconnectAttempts}] to: {target.Scheme}://{target.Host}:{target.Port} in-progress");
                                 provider = ProviderFactory.Create(target);
-                                await provider.Connect(connectionInfo).ConfigureAwait(false);
-                                await InitializeNewConnection(provider).ConfigureAwait(false);
+                                await provider.Connect(connectionInfo).Await();
+                                await InitializeNewConnection(provider).Await();
                                 return;
                             }
                             catch (Exception e)
@@ -173,7 +174,7 @@ namespace Apache.NMS.AMQP.Provider.Failover
                         }
                         else
                         {
-                            await reconnectControl.ScheduleReconnect(Reconnect).ConfigureAwait(false);
+                            await reconnectControl.ScheduleReconnect(Reconnect).Await();
                         }
                     }
                 }
@@ -220,21 +221,21 @@ namespace Apache.NMS.AMQP.Provider.Failover
                 Tracer.Debug($"Signalling connection recovery: {provider}");
 
                 // Allow listener to recover its resources
-                await listener.OnConnectionRecovery(provider).ConfigureAwait(false);
+                await listener.OnConnectionRecovery(provider).Await();
 
                 // Restart consumers, send pull commands, etc.
-                await listener.OnConnectionRecovered(provider).ConfigureAwait(false);
+                await listener.OnConnectionRecovered(provider).Await();
 
                 // Let the client know that connection has restored.
                 listener.OnConnectionRestored(connectedUri);
 
                 // If we try to run pending requests right after the connection is reestablished 
                 // it will result in timeout on the first send request
-                await Task.Delay(50).ConfigureAwait(false);
+                await Task.Delay(50).Await();
 
                 foreach (FailoverRequest request in GetPendingRequests())
                 {
-                    await request.Run().ConfigureAwait(false);
+                    await request.Run().Await();
                 }
 
                 reconnectControl.ConnectionEstablished();
@@ -266,6 +267,21 @@ namespace Apache.NMS.AMQP.Provider.Failover
             }
         }
 
+        public async Task CloseAsync()
+        {
+            if (closed.CompareAndSet(false, true))
+            {
+                try
+                {
+                    if (provider != null) await provider.CloseAsync().Await();
+                }
+                catch (Exception e)
+                {
+                    Tracer.Warn("Error caught while closing Provider: " + e.Message);
+                }
+            }
+        }
+
         public void SetProviderListener(IProviderListener providerListener)
         {
             CheckClosed();
@@ -599,20 +615,20 @@ namespace Apache.NMS.AMQP.Provider.Failover
                     if (ReconnectAttempts == 0)
                     {
                         Tracer.Debug("Initial connect attempt will be performed immediately");
-                        await action();
+                        await action().Await();;
                     }
                     else if (ReconnectAttempts == 1 && failoverProvider.InitialReconnectDelay > 0)
                     {
                         Tracer.Debug($"Delayed initial reconnect attempt will be in {failoverProvider.InitialReconnectDelay} milliseconds");
-                        await Task.Delay(TimeSpan.FromMilliseconds(failoverProvider.InitialReconnectDelay));
-                        await action();
+                        await Task.Delay(TimeSpan.FromMilliseconds(failoverProvider.InitialReconnectDelay)).Await();;
+                        await action().Await();;
                     }
                     else
                     {
                         double delay = NextReconnectDelay();
                         Tracer.Debug($"Next reconnect attempt will be in {delay} milliseconds");
-                        await Task.Delay(TimeSpan.FromMilliseconds(delay));
-                        await action();
+                        await Task.Delay(TimeSpan.FromMilliseconds(delay)).Await();;
+                        await action().Await();;
                     }
                 }
                 else if (ReconnectAttempts == 0)
@@ -620,21 +636,21 @@ namespace Apache.NMS.AMQP.Provider.Failover
                     if (failoverProvider.InitialReconnectDelay > 0)
                     {
                         Tracer.Debug($"Delayed initial reconnect attempt will be in {failoverProvider.InitialReconnectDelay} milliseconds");
-                        await Task.Delay(TimeSpan.FromMilliseconds(failoverProvider.InitialReconnectDelay));
-                        await action();
+                        await Task.Delay(TimeSpan.FromMilliseconds(failoverProvider.InitialReconnectDelay)).Await();
+                        await action().Await();;
                     }
                     else
                     {
                         Tracer.Debug("Initial Reconnect attempt will be performed immediately");
-                        await action();
+                        await action().Await();;
                     }
                 }
                 else
                 {
                     double delay = NextReconnectDelay();
                     Tracer.Debug($"Next reconnect attempt will be in {delay} milliseconds");
-                    await Task.Delay(TimeSpan.FromMilliseconds(delay));
-                    await action();
+                    await Task.Delay(TimeSpan.FromMilliseconds(delay)).Await();
+                    await action().Await();;
                 }
             }
 
diff --git a/src/NMS.AMQP/Provider/Failover/FailoverRequest.cs b/src/NMS.AMQP/Provider/Failover/FailoverRequest.cs
index 6c2ef6f..84f5822 100644
--- a/src/NMS.AMQP/Provider/Failover/FailoverRequest.cs
+++ b/src/NMS.AMQP/Provider/Failover/FailoverRequest.cs
@@ -20,6 +20,7 @@ using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 using Apache.NMS.AMQP.Meta;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Provider.Failover
 {
@@ -61,7 +62,7 @@ namespace Apache.NMS.AMQP.Provider.Failover
             {
                 try
                 {
-                    await this.DoTask(activeProvider).ConfigureAwait(false);
+                    await this.DoTask(activeProvider).Await();
                     this.taskCompletionSource.TrySetResult(true);
                     this.failoverProvider.RemoveFailoverRequest(this);
                     this.cancellationTokenSource?.Dispose();
diff --git a/src/NMS.AMQP/Provider/IProvider.cs b/src/NMS.AMQP/Provider/IProvider.cs
index afe3402..b92b829 100644
--- a/src/NMS.AMQP/Provider/IProvider.cs
+++ b/src/NMS.AMQP/Provider/IProvider.cs
@@ -30,6 +30,7 @@ namespace Apache.NMS.AMQP.Provider
         void Start();
         Task Connect(NmsConnectionInfo connectionInfo);
         void Close();
+        Task CloseAsync();
         void SetProviderListener(IProviderListener providerListener);
         Task CreateResource(INmsResource resourceInfo);
         Task DestroyResource(INmsResource resourceInfo);
diff --git a/src/NMS.AMQP/SessionDispatcher.cs b/src/NMS.AMQP/SessionDispatcher.cs
index fed3327..70d26e4 100644
--- a/src/NMS.AMQP/SessionDispatcher.cs
+++ b/src/NMS.AMQP/SessionDispatcher.cs
@@ -18,13 +18,14 @@
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks.Dataflow;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP
 {
     internal class SessionDispatcher
     {
         private readonly ActionBlock<NmsMessageConsumer.MessageDeliveryTask> actionBlock;
-        private int dispatchThreadId;
+        private readonly AsyncLocal<bool> isOnDispatcherFlow = new AsyncLocal<bool>();
         private readonly CancellationTokenSource cts;
 
         public SessionDispatcher()
@@ -40,18 +41,18 @@ namespace Apache.NMS.AMQP
 
         public void Post(NmsMessageConsumer.MessageDeliveryTask task) => actionBlock.Post(task);
 
-        public bool IsOnDeliveryThread() => dispatchThreadId == Thread.CurrentThread.ManagedThreadId;
+        public bool IsOnDeliveryExecutionFlow() => isOnDispatcherFlow.Value;
 
-        private void HandleTask(NmsMessageConsumer.MessageDeliveryTask messageDeliveryTask)
+        private async Task HandleTask(NmsMessageConsumer.MessageDeliveryTask messageDeliveryTask)
         {
             try
             {
-                dispatchThreadId = Thread.CurrentThread.ManagedThreadId;
-                messageDeliveryTask.DeliverNextPending();
+                isOnDispatcherFlow.Value = true;
+                await messageDeliveryTask.DeliverNextPending().Await();
             }
             finally
             {
-                dispatchThreadId = -1;
+                isOnDispatcherFlow.Value = false;
             }
         }
 
diff --git a/src/NMS.AMQP/Util/PriorityMessageQueue.cs b/src/NMS.AMQP/Util/PriorityMessageQueue.cs
index 3b11e1d..9d49618 100644
--- a/src/NMS.AMQP/Util/PriorityMessageQueue.cs
+++ b/src/NMS.AMQP/Util/PriorityMessageQueue.cs
@@ -17,8 +17,9 @@
 
 using System;
 using System.Collections.Generic;
-using System.Threading;
+using System.Threading.Tasks;
 using Apache.NMS.AMQP.Message;
+using Apache.NMS.AMQP.Util.Synchronization;
 
 namespace Apache.NMS.AMQP.Util
 {
@@ -26,8 +27,8 @@ namespace Apache.NMS.AMQP.Util
     {
         private readonly LinkedList<InboundMessageDispatch>[] lists;
 
-        private readonly object syncRoot = new object();
-
+        private readonly NmsSynchronizationMonitor syncRoot = new NmsSynchronizationMonitor();
+        
         private bool disposed;
         private int count;
 
@@ -46,8 +47,10 @@ namespace Apache.NMS.AMQP.Util
         {
             get
             {
-                lock (syncRoot)
+                using(syncRoot.Lock())
+                {
                     return count;
+                }
             }
         }
 
@@ -78,22 +81,26 @@ namespace Apache.NMS.AMQP.Util
 
         public void Enqueue(InboundMessageDispatch envelope)
         {
-            lock (syncRoot)
+            using(syncRoot.Lock())
             {
                 GetList(envelope).AddLast(envelope);
                 this.count++;
-                Monitor.Pulse(syncRoot);
+
+                syncRoot.Pulse();
             }
+            
+            
         }
         
         public void EnqueueFirst(InboundMessageDispatch envelope)
         {
-            lock (syncRoot)
+            using(syncRoot.Lock())
             {
                 lists[(int) MsgPriority.Highest].AddFirst(envelope);
                 count++;
-                Monitor.Pulse(syncRoot);
-            }            
+                syncRoot.Pulse();
+            }
+            
         }
 
         private LinkedList<InboundMessageDispatch> GetList(InboundMessageDispatch envelope)
@@ -102,20 +109,49 @@ namespace Apache.NMS.AMQP.Util
             return lists[(int) priority];
         }
 
+        public async Task<InboundMessageDispatch> DequeueAsync(int timeout)
+        {
+            using(await syncRoot.LockAsync())
+            {
+                while (timeout != 0 && IsEmpty && !disposed)
+                {
+                    if (timeout == -1)
+                    {
+                        await syncRoot.WaitAsync();
+                    }
+                    else
+                    {
+                        long start = DateTime.UtcNow.Ticks / 10_000L;
+                        await syncRoot.WaitAsync(timeout);
+                        timeout = Math.Max(timeout + (int) (start - DateTime.UtcNow.Ticks / 10_000L), 0);
+                    }
+                }
+
+                if (IsEmpty || disposed)
+                {
+                    return null;
+                }
+
+                return RemoveFirst();
+            }
+
+        }
+
+
         public InboundMessageDispatch Dequeue(int timeout)
         {
-            lock (syncRoot)
+            using(syncRoot.Lock())
             {
                 while (timeout != 0 && IsEmpty && !disposed)
                 {
                     if (timeout == -1)
                     {
-                        Monitor.Wait(syncRoot);
+                        syncRoot.Wait();
                     }
                     else
                     {
                         long start = DateTime.UtcNow.Ticks / 10_000L;
-                        Monitor.Wait(syncRoot, timeout);
+                        syncRoot.Wait(timeout);
                         timeout = Math.Max(timeout + (int) (start - DateTime.UtcNow.Ticks / 10_000L), 0);
                     }
                 }
@@ -127,27 +163,32 @@ namespace Apache.NMS.AMQP.Util
 
                 return RemoveFirst();
             }
+            
         }
         
         public void Clear()
         {
-            lock (syncRoot)
-            {                
+            using(syncRoot.Lock())
+            {
                 for (int i = (int) MsgPriority.Highest; i >= 0; i--)
                 {
                     lists[i].Clear();
                 }
+
                 count = 0;
             }
+            
         }
 
         public void Dispose()
         {
-            lock (syncRoot)
+            
+            using(syncRoot.Lock())
             {
                 disposed = true;
-                Monitor.PulseAll(syncRoot);
+                syncRoot.PulseAll();
             }
+            
         }
     }
 }
\ No newline at end of file
diff --git a/src/NMS.AMQP/Util/SymbolUtil.cs b/src/NMS.AMQP/Util/SymbolUtil.cs
index e3fe2c3..5b23b57 100644
--- a/src/NMS.AMQP/Util/SymbolUtil.cs
+++ b/src/NMS.AMQP/Util/SymbolUtil.cs
@@ -14,13 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+
 using Amqp.Types;
-using Apache.NMS;
 
 namespace Apache.NMS.AMQP.Util
 {
diff --git a/src/NMS.AMQP/Util/Synchronization/NmsSynchronizationMonitor.cs b/src/NMS.AMQP/Util/Synchronization/NmsSynchronizationMonitor.cs
new file mode 100644
index 0000000..98a13f9
--- /dev/null
+++ b/src/NMS.AMQP/Util/Synchronization/NmsSynchronizationMonitor.cs
@@ -0,0 +1,280 @@
+/*
+ * 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 System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.NMS.AMQP.Util.Synchronization
+{
+    /// <summary>
+    /// Goal of this is to replace lock(syncRoot) for sync and async methods, and also have Wait and Pulse(All) capabilities
+    /// Relies on AsyncLocal construct, and should be valid along the flow of executioncontext
+    /// </summary>
+    public class NmsSynchronizationMonitor
+    {
+        // Main locking mechanism
+        private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
+
+        // Lists of executions sleeping in Wait
+        private readonly List<SemaphoreSlim> waitingLocks = new List<SemaphoreSlim>();
+
+        // SyncRoot used in locking related to Wait/Pulse
+        private readonly object waitSyncRoot = new object();
+
+        // Holds RALock in current flow of execution, should be like ThreadStatic but for async flow
+        private readonly AsyncLocal<NmsLock> asyncLocal;
+
+        public NmsSynchronizationMonitor()
+        {
+            asyncLocal = new AsyncLocal<NmsLock>();
+        }
+
+        /// <summary>
+        /// Synchronous Wait operation
+        /// </summary>
+        /// <param name="timeout"></param>
+        public void Wait(int? timeout = null)
+        {
+            var raLock = GetCurrentLock();
+
+            if (raLock == null)
+            {
+                throw new IllegalStateException("Wait called without acquiring Lock first");
+            }
+
+            // In one synchronized context we will Release monitor and sign ourself on list of sleeping locks
+            SemaphoreSlim waitSemaphore = new SemaphoreSlim(0, 1);
+            lock (waitSyncRoot)
+            {
+                ReleaseMonitor();
+                waitingLocks.Add(waitSemaphore);
+                // raLock.WaitSemaphore = new SemaphoreSlim(0, 1);
+            }
+
+            try
+            {
+                // Now wait, if our lock was pulsed just before, we will not really sleep, but instead continue ...
+                waitSemaphore.Wait(timeout ?? -1);
+
+                lock (waitSyncRoot)
+                {
+                    waitingLocks.Remove(waitSemaphore);
+                    waitSemaphore.Dispose();
+                }
+            }
+            finally
+            {
+                // Enter again, but we need to use the same raLock as before
+                EnterMonitor();
+            }
+        }
+
+
+        public async Task WaitAsync(int? timeout = null)
+        {
+            var raLock = GetCurrentLock();
+
+            if (raLock == null)
+            {
+                throw new IllegalStateException("Wait called without acquiring Lock first");
+            }
+
+            SemaphoreSlim waitSemaphore = new SemaphoreSlim(0, 1);
+
+            lock (waitSyncRoot)
+            {
+                ReleaseMonitor();
+                waitingLocks.Add(waitSemaphore);
+            }
+
+            try
+            {
+                // Here between lock and waiting is a problematic thing, two pulses can release the same thing
+                await waitSemaphore.WaitAsync(timeout ?? -1).Await();
+
+                lock (waitSyncRoot)
+                {
+                    waitingLocks.Remove(waitSemaphore);
+                    waitSemaphore.Dispose();
+                    waitSemaphore.Dispose();
+                }
+            }
+            finally
+            {
+                // Enter again, but we need to use the same raLock as before, and also asyncLocal a
+                await EnterMonitorAsync().Await();
+            }
+        }
+
+        public void Pulse()
+        {
+            lock (waitSyncRoot)
+            {
+                var firstWaiting = waitingLocks.FirstOrDefault();
+                if (firstWaiting != null)
+                {
+                    firstWaiting.Release();
+                    waitingLocks.Remove(firstWaiting);
+                }
+            }
+        }
+
+        public void PulseAll()
+        {
+            lock (waitSyncRoot)
+            {
+                waitingLocks.ForEach(a => { a.Release(); });
+                waitingLocks.Clear();
+            }
+        }
+
+
+        /// <summary>
+        /// Allows to create a sub context where asyncLocal will be removed and thus not passed for example to something that could carry it and thus has wrong locks acquired
+        /// </summary>
+        /// <returns></returns>
+        public IDisposable Exclude()
+        {
+            return new ExcludeLock(this);
+        }
+
+
+        public IDisposable Lock()
+        {
+            NmsLock nmsLock = GetOrCreateCurrentLock();
+            nmsLock.Enter();
+            return nmsLock;
+        }
+
+        public Task<IDisposable>
+            LockAsync() // This should not be async method, cause setting asyncLocal inside GetOrCreateCurrentLock may be only limited to this method in such case
+        {
+            NmsLock nmsLock = GetOrCreateCurrentLock();
+            return nmsLock.EnterAsync();
+        }
+
+
+        private NmsLock GetOrCreateCurrentLock()
+        {
+            if (asyncLocal.Value == null)
+            {
+                asyncLocal.Value = new NmsLock(this);
+            }
+
+            return asyncLocal.Value;
+        }
+
+        private NmsLock GetCurrentLock()
+        {
+            var context = asyncLocal.Value;
+            return context;
+        }
+
+        private void SetCurrentLock(NmsLock nmsLock)
+        {
+            asyncLocal.Value = nmsLock;
+        }
+
+        private void EnterMonitor()
+        {
+            semaphoreSlim.Wait();
+        }
+
+        private Task EnterMonitorAsync()
+        {
+            return semaphoreSlim.WaitAsync();
+        }
+
+        private void ReleaseMonitor()
+        {
+            semaphoreSlim.Release();
+        }
+
+        private class NmsLock : IDisposable
+        {
+            private int NestCounter { get; set; }
+
+            public Guid Id = Guid.NewGuid();
+
+            private readonly NmsSynchronizationMonitor parent;
+
+            public NmsLock(NmsSynchronizationMonitor parent)
+            {
+                this.parent = parent;
+            }
+
+            public void Enter()
+            {
+                if (NestCounter == 0)
+                {
+                    parent.EnterMonitor();
+                }
+
+                NestCounter++;
+            }
+
+            public async Task<IDisposable> EnterAsync()
+            {
+                if (NestCounter == 0)
+                {
+                    await parent.EnterMonitorAsync();
+                }
+
+                NestCounter++;
+                return this;
+            }
+
+            private void Leave()
+            {
+                NestCounter--;
+                if (NestCounter <= 0)
+                {
+                    parent.ReleaseMonitor();
+                    parent.SetCurrentLock(null);
+                }
+            }
+
+            public void Dispose()
+            {
+                Leave();
+            }
+        }
+        
+        private class ExcludeLock : IDisposable
+        {
+            private readonly NmsSynchronizationMonitor parent;
+
+            private readonly NmsLock currentLock;
+
+            public ExcludeLock(NmsSynchronizationMonitor parent)
+            {
+                this.parent = parent;
+
+                currentLock = parent.GetCurrentLock();
+                parent.SetCurrentLock(null);
+            }
+
+            public void Dispose()
+            {
+                parent.SetCurrentLock(this.currentLock);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/NMS.AMQP/Util/Synchronization/TaskExtensions.cs b/src/NMS.AMQP/Util/Synchronization/TaskExtensions.cs
new file mode 100644
index 0000000..e5e4072
--- /dev/null
+++ b/src/NMS.AMQP/Util/Synchronization/TaskExtensions.cs
@@ -0,0 +1,66 @@
+/*
+ * 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.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+namespace Apache.NMS.AMQP.Util.Synchronization
+{
+    public static class TaskExtensions
+    {
+        
+        public static T GetAsyncResult<T>(this Task<T> task)
+        {
+            return task.Await().GetAwaiter().GetResult();
+        }
+        
+        public static void GetAsyncResult(this Task task)
+        {
+            task.Await().GetAwaiter().GetResult();
+        }
+
+        public static async Task AwaitRunContinuationAsync(this Task task)
+        {
+            await task.Await();
+            if (TaskSynchronizationSettings.TryToRunCertainContunuationsAsynchronously)
+            {
+                await Task.Yield();
+            }
+        }
+        
+        public static async Task<T> AwaitRunContinuationAsync<T>(this Task<T> task)
+        {
+            T t = await task.Await();
+            if (TaskSynchronizationSettings.TryToRunCertainContunuationsAsynchronously)
+            {
+                await Task.Yield();
+            }
+            return t;
+        }
+        
+        public static ConfiguredTaskAwaitable Await(this Task task)
+        {
+            return task.ConfigureAwait(TaskSynchronizationSettings.ContinueOnCapturedContext);
+        }
+        
+        public static ConfiguredTaskAwaitable<T> Await<T>(this Task<T> task)
+        {
+            return task.ConfigureAwait(TaskSynchronizationSettings.ContinueOnCapturedContext);
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/src/NMS.AMQP/Util/Synchronization/TaskSynchronizationSettings.cs b/src/NMS.AMQP/Util/Synchronization/TaskSynchronizationSettings.cs
new file mode 100644
index 0000000..fa2e3b4
--- /dev/null
+++ b/src/NMS.AMQP/Util/Synchronization/TaskSynchronizationSettings.cs
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+namespace Apache.NMS.AMQP.Util.Synchronization
+{
+    
+    public static class TaskSynchronizationSettings
+    {
+        /// <summary>
+        /// General settings for awaits, whether to force continuation on captured context
+        /// </summary>
+        public static bool ContinueOnCapturedContext { get; set; } = false;
+
+        /// <summary>
+        /// In AMQP library there is a async pump, that is calling methods, and in turn continuation may be inlined, if this happens
+        /// and continuation is waiting synchronously on something, then it stops processing in that pump, and it may lead to deadlocks
+        /// if continuation is waiting on something (some message) that async pump was supposed to deliver-but now async pump stopped processing
+        /// It seems it was also discussed here https://github.com/Azure/amqpnetlite/issues/237
+        /// So by default there is a try to force continuation from different thread (by using) yield, on those tasks that it seems that their
+        /// continuation may be from async pump
+        /// </summary>
+        public static bool TryToRunCertainContunuationsAsynchronously { get; set; } = true;
+    }
+}
\ No newline at end of file
diff --git a/src/NMS.AMQP/Util/UriUtil.cs b/src/NMS.AMQP/Util/UriUtil.cs
index acfbef8..ad06886 100644
--- a/src/NMS.AMQP/Util/UriUtil.cs
+++ b/src/NMS.AMQP/Util/UriUtil.cs
@@ -15,12 +15,7 @@
  * limitations under the License.
  */
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using Amqp;
-using Apache.NMS;
 
 namespace Apache.NMS.AMQP.Util
 {
diff --git a/test/Apache-NMS-AMQP-Interop-Test/Transactions/NmsTransactedConsumerTest.cs b/test/Apache-NMS-AMQP-Interop-Test/Transactions/NmsTransactedConsumerTest.cs
index 37dbd29..55c4eee 100644
--- a/test/Apache-NMS-AMQP-Interop-Test/Transactions/NmsTransactedConsumerTest.cs
+++ b/test/Apache-NMS-AMQP-Interop-Test/Transactions/NmsTransactedConsumerTest.cs
@@ -46,6 +46,8 @@ namespace NMS.AMQP.Test.Transactions
         [Test, Timeout(60_000)]
         public void TestConsumedInTxAreAcked()
         {
+            PurgeQueue(TimeSpan.FromSeconds(2));
+            
             Connection = CreateAmqpConnection();
             Connection.Start();
 
diff --git a/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs
index ba09d9c..2609400 100644
--- a/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs
@@ -18,6 +18,7 @@
 using System;
 using System.Collections.Generic;
 using System.Threading;
+using System.Threading.Tasks;
 using Amqp.Framing;
 using Apache.NMS;
 using Apache.NMS.AMQP.Util;
diff --git a/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/AmqpAcknowledgmentsIntegrationTest.cs
similarity index 68%
copy from test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs
copy to test/Apache-NMS-AMQP-Test/Integration/Async/AmqpAcknowledgmentsIntegrationTest.cs
index ba09d9c..b419ad4 100644
--- a/test/Apache-NMS-AMQP-Test/Integration/AmqpAcknowledgmentsIntegrationTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/AmqpAcknowledgmentsIntegrationTest.cs
@@ -18,72 +18,73 @@
 using System;
 using System.Collections.Generic;
 using System.Threading;
+using System.Threading.Tasks;
 using Amqp.Framing;
 using Apache.NMS;
 using Apache.NMS.AMQP.Util;
 using NMS.AMQP.Test.TestAmqp;
 using NUnit.Framework;
 
-namespace NMS.AMQP.Test.Integration
+namespace NMS.AMQP.Test.Integration.Async
 {
     [TestFixture]
-    public class AmqpAcknowledgmentsIntegrationTest : IntegrationTestFixture
+    public class AmqpAcknowledgmentsIntegrationTestAsync : IntegrationTestFixture
     {
         [Test, Timeout(20_000)]
-        public void TestAcknowledgeFailsAfterSessionIsClosed()
+        public async Task TestAcknowledgeFailsAfterSessionIsClosed()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: 1);
                 testPeer.ExpectEnd();
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
-                IMessage receivedMessage = consumer.Receive(TimeSpan.FromSeconds(6));
+                IMessage receivedMessage = await consumer.ReceiveAsync(TimeSpan.FromSeconds(6));
                 Assert.NotNull(receivedMessage, "Message was not received");
                 
-                session.Close();
+                await session.CloseAsync();
 
-                Assert.Catch<NMSException>(() => receivedMessage.Acknowledge(), "Should not be able to acknowledge the message after session closed");
+                Assert.CatchAsync<NMSException>(async () => await receivedMessage.AcknowledgeAsync(), "Should not be able to acknowledge the message after session closed");
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestClientAcknowledgeMessages()
+        public async Task TestClientAcknowledgeMessages()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 3;
                 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
                 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: msgCount);
                 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
                 
                 IMessage lastReceivedMessage = null;
                 for (int i = 0; i < msgCount; i++)
                 {
-                    lastReceivedMessage = consumer.Receive();
+                    lastReceivedMessage = await consumer.ReceiveAsync();
                     Assert.NotNull(lastReceivedMessage, "Message " + i + " was not received");
                 }
                 
@@ -92,35 +93,35 @@ namespace NMS.AMQP.Test.Integration
                     testPeer.ExpectDispositionThatIsAcceptedAndSettled();
                 }
                 
-                lastReceivedMessage.Acknowledge();
+                await lastReceivedMessage.AcknowledgeAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(2000);
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestClientAcknowledgeMessagesAsync()
+        public async Task TestClientAcknowledgeMessagesAsync()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 3;
 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
                 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: msgCount);
                 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 CountdownEvent latch = new CountdownEvent(3);
 
@@ -138,30 +139,30 @@ namespace NMS.AMQP.Test.Integration
                     testPeer.ExpectDispositionThatIsAcceptedAndSettled();
                 }
                 
-                lastReceivedMessage.Acknowledge();
+                await lastReceivedMessage.AcknowledgeAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(2000);
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestAcknowledgeIndividualMessages()
+        public async Task TestAcknowledgeIndividualMessages()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 6;
 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.IndividualAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.IndividualAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
                 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(
@@ -174,12 +175,12 @@ namespace NMS.AMQP.Test.Integration
                     sendSettled: false,
                     creditMatcher: credit => Assert.Greater(credit, msgCount));
                 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
                 
                 var messages = new List<IMessage>();
                 for (int i = 0; i < msgCount; i++)
                 {
-                    IMessage message = consumer.Receive(TimeSpan.FromMilliseconds(3000));
+                    IMessage message = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000));
                     Assert.NotNull(message, "Message " + i + " was not received");
                     messages.Add(message);
                     
@@ -199,31 +200,31 @@ namespace NMS.AMQP.Test.Integration
 
                     testPeer.ExpectDisposition(settled: true, stateMatcher: dispositionMatcher, firstDeliveryId: deliveryNumber, lastDeliveryId: deliveryNumber);
                     
-                    message.Acknowledge();
+                    await message.AcknowledgeAsync();
                     
                     testPeer.WaitForAllMatchersToComplete(3000);
                 }
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestAcknowledgeIndividualMessagesAsync()
+        public async Task TestAcknowledgeIndividualMessagesAsync()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 6;
 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.IndividualAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.IndividualAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(
@@ -236,7 +237,7 @@ namespace NMS.AMQP.Test.Integration
                     sendSettled: false,
                     creditMatcher: credit => Assert.Greater(credit, msgCount));
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
                 
                 CountdownEvent latch = new CountdownEvent(msgCount);
                 List<ITextMessage> messages = new List<ITextMessage>();
@@ -261,70 +262,70 @@ namespace NMS.AMQP.Test.Integration
 
                     testPeer.ExpectDisposition(settled: true, stateMatcher: dispositionMatcher, firstDeliveryId: deliveryNumber, lastDeliveryId: deliveryNumber);
                     
-                    message.Acknowledge();
+                    await message.AcknowledgeAsync();
                     
                     testPeer.WaitForAllMatchersToComplete(3000);
                 }
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestAutoAcknowledgeMessages()
+        public async Task TestAutoAcknowledgeMessages()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 6;
 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: msgCount);
                 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 for (int i = 0; i < msgCount; i++) 
                     testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
                 for (int i = 0; i < msgCount; i++) 
-                    Assert.NotNull(consumer.Receive(TimeSpan.FromMilliseconds(3000)), $"Message {i} not received within given timeout.");
+                    Assert.NotNull(await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000)), $"Message {i} not received within given timeout.");
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestAutoAcknowledgeMessagesAsync()
+        public async Task TestAutoAcknowledgeMessagesAsync()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
                 int msgCount = 6;
 
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: msgCount);
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 for (int i = 0; i < msgCount; i++)
                     testPeer.ExpectDispositionThatIsAcceptedAndSettled();
@@ -334,7 +335,7 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(3000);
                 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
                 
                 testPeer.WaitForAllMatchersToComplete(3000);
             }
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/ConnectionIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/ConnectionIntegrationTest.cs
new file mode 100644
index 0000000..03e2b29
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/ConnectionIntegrationTest.cs
@@ -0,0 +1,254 @@
+/*
+ * 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 System.Threading;
+using System.Threading.Tasks;
+using Apache.NMS;
+using Apache.NMS.AMQP;
+using NMS.AMQP.Test.TestAmqp;
+using NMS.AMQP.Test.TestAmqp.BasicTypes;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class ConnectionIntegrationTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestCreateAndCloseConnection()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestExplicitConnectionCloseListenerIsNotInvoked()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent exceptionFired = new ManualResetEvent(false);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                connection.ExceptionListener += exception => { exceptionFired.Set(); };
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                Assert.IsFalse(exceptionFired.WaitOne(TimeSpan.FromMilliseconds(100)));
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestCreateAutoAckSession()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                Assert.NotNull(session, "Session should not be null");
+                testPeer.ExpectClose();
+                Assert.AreEqual(AcknowledgementMode.AutoAcknowledge, session.AcknowledgementMode);
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateAutoAckSessionByDefault()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync();
+                Assert.NotNull(session, "Session should not be null");
+                Assert.AreEqual(AcknowledgementMode.AutoAcknowledge, session.AcknowledgementMode);
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyCloseConnectionDuringSessionCreation()
+        {
+            string errorMessage = "buba";
+
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+
+                // Expect the begin, then explicitly close the connection with an error
+                testPeer.ExpectBegin(sendResponse: false);
+                testPeer.RemotelyCloseConnection(expectCloseResponse: true, errorCondition: AmqpError.NOT_ALLOWED, errorMessage: errorMessage);
+
+                try
+                {
+                    await connection.CreateSessionAsync();
+                    Assert.Fail("Expected exception to be thrown");
+                }
+                catch (NMSException e)
+                {
+                    Assert.True(e.Message.Contains(errorMessage));
+                }
+
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyEndConnectionListenerInvoked()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent done = new ManualResetEvent(false);
+
+                // Don't set a ClientId, so that the underlying AMQP connection isn't established yet
+                IConnection connection = await EstablishConnectionAsync(testPeer: testPeer, setClientId: false);
+
+                // Tell the test peer to close the connection when executing its last handler
+                testPeer.RemotelyCloseConnection(expectCloseResponse: true, errorCondition: ConnectionError.CONNECTION_FORCED, errorMessage: "buba");
+
+                connection.ExceptionListener += exception => done.Set();
+
+                // Trigger the underlying AMQP connection
+                await connection.StartAsync();
+
+                Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(5)), "Connection should report failure");
+
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyEndConnectionWithSessionWithConsumer()
+        {
+            string errorMessage = "buba";
+
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                // Create a consumer, then remotely end the connection afterwards.
+                testPeer.ExpectReceiverAttach();
+ 
+                testPeer.ExpectLinkFlow();
+                testPeer.RemotelyCloseConnection(expectCloseResponse: true, errorCondition: AmqpError.RESOURCE_LIMIT_EXCEEDED, errorMessage: errorMessage);
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+
+                Assert.That(() => ((NmsConnection) connection).IsConnected, Is.False.After(10_000, 100), "Connection never closes.");
+
+                try
+                {
+                    await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                    Assert.Fail("Expected ISE to be thrown due to being closed");
+                }
+                catch (NMSConnectionException e)
+                {
+                    Assert.True(e.ToString().Contains(AmqpError.RESOURCE_LIMIT_EXCEEDED));
+                    Assert.True(e.ToString().Contains(errorMessage));
+                }
+
+                // Verify the session is now marked closed
+                try
+                {
+                    var _ = session.AcknowledgementMode;
+                    Assert.Fail("Expected ISE to be thrown due to being closed");
+                }
+                catch (IllegalStateException e)
+                {
+                    Assert.True(e.ToString().Contains(AmqpError.RESOURCE_LIMIT_EXCEEDED));
+                    Assert.True(e.ToString().Contains(errorMessage));
+                }
+
+                // Verify the consumer is now marked closed
+                try
+                {
+                    consumer.Listener += message => { };
+                }
+                catch (IllegalStateException e)
+                {
+                    Assert.True(e.ToString().Contains(AmqpError.RESOURCE_LIMIT_EXCEEDED));
+                    Assert.True(e.ToString().Contains(errorMessage));
+                }
+                
+                // Try closing them explicitly, should effectively no-op in client.
+                // The test peer will throw during close if it sends anything.
+                await consumer.CloseAsync();
+                await session.CloseAsync();
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestConnectionStartStop()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                int msgCount = 10;
+
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithNullContent(), count: msgCount);
+                
+                var consumer = await session.CreateConsumerAsync(queue);
+
+                for (int i = 0; i < 5; i++)
+                {
+                    IMessage message = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(1000));
+                    Assert.IsNotNull(message);
+                }
+                
+                // stop the connection, consumers shouldn't receive any more messages
+                await connection.StopAsync();
+                
+                // No messages should arrive to consumer as connection has been stopped
+                Assert.IsNull(await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(100)), "Message arrived despite the fact, that the connection was stopped.");
+                
+                // restart the connection
+                await connection.StartAsync();
+                
+                // The second batch of messages should be delivered
+                for (int i = 0; i < 5; i++)
+                {
+                    IMessage message = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(1000));
+                    Assert.IsNotNull(message);
+                }
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(2000);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/ConsumerIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/ConsumerIntegrationTest.cs
similarity index 66%
copy from test/Apache-NMS-AMQP-Test/Integration/ConsumerIntegrationTest.cs
copy to test/Apache-NMS-AMQP-Test/Integration/Async/ConsumerIntegrationTest.cs
index cdb25e6..b4f9885 100644
--- a/test/Apache-NMS-AMQP-Test/Integration/ConsumerIntegrationTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/ConsumerIntegrationTest.cs
@@ -29,37 +29,37 @@ using NMS.AMQP.Test.TestAmqp;
 using NMS.AMQP.Test.TestAmqp.BasicTypes;
 using NUnit.Framework;
 
-namespace NMS.AMQP.Test.Integration
+namespace NMS.AMQP.Test.Integration.Async
 {
     [TestFixture]
-    public class ConsumerIntegrationTest : IntegrationTestFixture
+    public class ConsumerIntegrationTestAsync : IntegrationTestFixture
     {
         [Test, Timeout(20_000)]
-        public void TestCloseConsumer()
+        public async Task TestCloseConsumer()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
                 testPeer.ExpectBegin();
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(1000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestRemotelyCloseConsumer()
+        public async Task TestRemotelyCloseConsumer()
         {
             Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
             string errorMessage = "buba";
@@ -73,20 +73,20 @@ namespace NMS.AMQP.Test.Integration
                     .Setup(listener => listener.OnConsumerClosed(It.IsAny<IMessageConsumer>(), It.IsAny<Exception>()))
                     .Callback(() => consumerClosed.Set());
 
-                NmsConnection connection = (NmsConnection) EstablishConnection(testPeer);
+                NmsConnection connection = (NmsConnection) await EstablishConnectionAsync(testPeer);
                 connection.AddConnectionListener(mockConnectionListener.Object);
                 connection.ExceptionListener += exception => { exceptionFired.Set(); };
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
 
                 // Create a consumer, then remotely end it afterwards.
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
                 testPeer.RemotelyDetachLastOpenedLinkOnLastOpenedSession(expectDetachResponse: true, closed: true, errorType: AmqpError.RESOURCE_DELETED, errorMessage: errorMessage, delayBeforeSend: 400);
 
-                IQueue queue = session.GetQueue("myQueue");
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 // Verify the consumer gets marked closed
                 testPeer.WaitForAllMatchersToComplete(1000);
@@ -96,12 +96,12 @@ namespace NMS.AMQP.Test.Integration
 
                 // Try closing it explicitly, should effectively no-op in client.
                 // The test peer will throw during close if it sends anything.
-                consumer.Close();
+                await consumer.CloseAsync();
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestRemotelyCloseConsumerWithMessageListenerFiresExceptionListener()
+        public async Task TestRemotelyCloseConsumerWithMessageListenerFiresExceptionListener()
         {
             Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
             string errorMessage = "buba";
@@ -115,20 +115,20 @@ namespace NMS.AMQP.Test.Integration
                     .Setup(listener => listener.OnConsumerClosed(It.IsAny<IMessageConsumer>(), It.IsAny<Exception>()))
                     .Callback(() => consumerClosed.Set());
 
-                NmsConnection connection = (NmsConnection) EstablishConnection(testPeer);
+                NmsConnection connection = (NmsConnection) await EstablishConnectionAsync(testPeer);
                 connection.AddConnectionListener(mockConnectionListener.Object);
                 connection.ExceptionListener += exception => { exceptionFired.Set(); };
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
 
                 // Create a consumer, then remotely end it afterwards.
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
                 testPeer.RemotelyDetachLastOpenedLinkOnLastOpenedSession(expectDetachResponse: true, closed: true, errorType: AmqpError.RESOURCE_DELETED, errorMessage: errorMessage, 10);
 
-                IQueue queue = session.GetQueue("myQueue");
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 consumer.Listener += message => { };
 
@@ -140,141 +140,141 @@ namespace NMS.AMQP.Test.Integration
 
                 // Try closing it explicitly, should effectively no-op in client.
                 // The test peer will throw during close if it sends anything.
-                consumer.Close();
+                await consumer.CloseAsync();
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestReceiveMessageWithReceiveZeroTimeout()
+        public async Task TestReceiveMessageWithReceiveZeroTimeout()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
 
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = null } }, count: 1);
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
-                IMessage message = consumer.Receive();
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+                IMessage message = await consumer.ReceiveAsync();
                 Assert.NotNull(message, "A message should have been received");
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(10000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestExceptionInOnMessageReleasesInAutoAckMode()
+        public async Task TestExceptionInOnMessageReleasesInAutoAckMode()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = null } }, count: 1);
                 testPeer.ExpectDispositionThatIsReleasedAndSettled();
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
                 consumer.Listener += message => throw new Exception();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(10000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestCloseDurableTopicSubscriberDetachesWithCloseFalse()
+        public async Task TestCloseDurableTopicSubscriberDetachesWithCloseFalse()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
 
                 string topicName = "myTopic";
                 string subscriptionName = "mySubscription";
-                ITopic topic = session.GetTopic(topicName);
+                ITopic topic = await session.GetTopicAsync(topicName);
 
                 testPeer.ExpectDurableSubscriberAttach(topicName, subscriptionName);
                 testPeer.ExpectLinkFlow();
 
-                IMessageConsumer durableConsumer = session.CreateDurableConsumer(topic, subscriptionName, null, false);
+                IMessageConsumer durableConsumer = await session.CreateDurableConsumerAsync(topic, subscriptionName, null, false);
 
                 testPeer.ExpectDetach(expectClosed: false, sendResponse: true, replyClosed: false);
-                durableConsumer.Close();
+                await durableConsumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(1000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerReceiveThrowsIfConnectionLost()
+        public async Task TestConsumerReceiveThrowsIfConnectionLost()
         {
-            DoTestConsumerReceiveThrowsIfConnectionLost(false);
+            await DoTestConsumerReceiveThrowsIfConnectionLost(false);
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerTimedReceiveThrowsIfConnectionLost()
+        public async Task TestConsumerTimedReceiveThrowsIfConnectionLost()
         {
-            DoTestConsumerReceiveThrowsIfConnectionLost(true);
+            await DoTestConsumerReceiveThrowsIfConnectionLost(true);
         }
 
-        private void DoTestConsumerReceiveThrowsIfConnectionLost(bool useTimeout)
+        private async Task DoTestConsumerReceiveThrowsIfConnectionLost(bool useTimeout)
         {
             ManualResetEvent consumerReady = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("queue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("queue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
                 testPeer.RunAfterLastHandler(() => { consumerReady.WaitOne(2000); });
                 testPeer.DropAfterLastMatcher(delay: 10);
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
                 consumerReady.Set();
 
                 try
                 {
                     if (useTimeout)
                     {
-                        consumer.Receive(TimeSpan.FromMilliseconds(10_0000));
+                        await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(10_0000));
                     }
                     else
                     {
-                        consumer.Receive();
+                        await consumer.ReceiveAsync();
                     }
 
 
@@ -290,13 +290,13 @@ namespace NMS.AMQP.Test.Integration
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerReceiveNoWaitThrowsIfConnectionLost()
+        public async Task TestConsumerReceiveNoWaitThrowsIfConnectionLost()
         {
             ManualResetEvent disconnected = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                NmsConnection connection = (NmsConnection) EstablishConnection(testPeer);
+                NmsConnection connection = (NmsConnection) await EstablishConnectionAsync(testPeer);
                 Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
 
                 connectionListener
@@ -305,18 +305,18 @@ namespace NMS.AMQP.Test.Integration
 
                 connection.AddConnectionListener(connectionListener.Object);
 
-                connection.Start();
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("queue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("queue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
                 testPeer.RemotelyCloseConnection(expectCloseResponse: true, errorCondition: ConnectionError.CONNECTION_FORCED, errorMessage: "buba");
 
-                IMessageConsumer consumer = session.CreateConsumer(queue);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
 
                 Assert.True(disconnected.WaitOne(), "Connection should be disconnected");
 
@@ -333,24 +333,24 @@ namespace NMS.AMQP.Test.Integration
         }
 
         [Test, Timeout(20_000)]
-        public void TestSetMessageListenerAfterStartAndSend()
+        public async Task TestSetMessageListenerAfterStartAndSend()
         {
             int messageCount = 4;
             CountdownEvent latch = new CountdownEvent(messageCount);
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), messageCount);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 for (int i = 0; i < messageCount; i++)
                 {
@@ -365,114 +365,114 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
 
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestNoReceivedMessagesWhenConnectionNotStarted()
+        public async Task TestNoReceivedMessagesWhenConnectionNotStarted()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 3);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 // Wait for a message to arrive then try and receive it, which should not happen
                 // since the connection is not started.
-                Assert.Null(consumer.Receive(TimeSpan.FromMilliseconds(100)));
+                Assert.Null(await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(100)));
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestNoReceivedNoWaitMessagesWhenConnectionNotStarted()
+        public async Task TestNoReceivedNoWaitMessagesWhenConnectionNotStarted()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 3);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 // Wait for a message to arrive then try and receive it, which should not happen
                 // since the connection is not started.
                 Assert.Null(consumer.ReceiveNoWait());
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestSyncReceiveFailsWhenListenerSet()
+        public async Task TestSyncReceiveFailsWhenListenerSet()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
+                IConnection connection = await EstablishConnectionAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 consumer.Listener += message => { };
 
-                Assert.Catch<NMSException>(() => consumer.Receive(), "Should have thrown an exception.");
-                Assert.Catch<NMSException>(() => consumer.Receive(TimeSpan.FromMilliseconds(1000)), "Should have thrown an exception.");
-                Assert.Catch<NMSException>(() => consumer.ReceiveNoWait(), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => await consumer.ReceiveAsync(), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(1000)), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => consumer.ReceiveNoWait(), "Should have thrown an exception.");
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestCreateProducerInOnMessage()
+        public async Task TestCreateProducerInOnMessage()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                IQueue outbound = session.GetQueue("ForwardDest");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IQueue outbound = await session.GetQueueAsync("ForwardDest");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
@@ -483,7 +483,7 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 consumer.Listener += message =>
                 {
@@ -495,30 +495,30 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(10_000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsConnectionCloseThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsConnectionCloseThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -545,33 +545,33 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsConnectionStopThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsConnectionStopThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -598,33 +598,33 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsSessionCloseThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsSessionCloseThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -651,10 +651,10 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
@@ -662,27 +662,27 @@ namespace NMS.AMQP.Test.Integration
 
         // TODO: To be fixed
         [Test, Timeout(20_000), Ignore("Ignore")]
-        public void TestMessageListenerClosesItsConsumer()
+        public async Task TestMessageListenerClosesItsConsumer()
         {
             var latch = new ManualResetEvent(false);
             var exceptionListenerFired = new ManualResetEvent(false);
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 connection.ExceptionListener += _ => exceptionListenerFired.Set();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectLinkFlow(drain: true, sendDrainFlowResponse: true, creditMatcher: credit => Assert.AreEqual(99, credit)); // Not sure if expected credit is right
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
@@ -708,7 +708,7 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 Assert.False(exceptionListenerFired.WaitOne(20), "Exception listener shouldn't have fired");
                 testPeer.WaitForAllMatchersToComplete(2000);
@@ -716,7 +716,7 @@ namespace NMS.AMQP.Test.Integration
         }
 
         [Test, Timeout(20_000)]
-        public void TestRecoverOrderingWithAsyncConsumer()
+        public async Task TestRecoverOrderingWithAsyncConsumer()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
             Exception asyncError = null;
@@ -728,14 +728,14 @@ namespace NMS.AMQP.Test.Integration
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(
@@ -749,7 +749,7 @@ namespace NMS.AMQP.Test.Integration
                     creditMatcher: credit => Assert.Greater(credit, messageCount)
                 );
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 bool complete = false;
                 int messageSeen = 0;
@@ -805,32 +805,32 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestConsumerCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -843,37 +843,37 @@ namespace NMS.AMQP.Test.Integration
                 Assert.True(latch.WaitOne(TimeSpan.FromMilliseconds(3000)), "Messages not received within given timeout.");
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestSessionCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestSessionCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -886,37 +886,37 @@ namespace NMS.AMQP.Test.Integration
                 Assert.True(latch.WaitOne(TimeSpan.FromMilliseconds(3000)), "Messages not received within given timeout.");
 
                 testPeer.ExpectEnd();
-                session.Close();
+                await session.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConnectionCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestConnectionCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
-                connection.Start();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                await connection.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -929,43 +929,43 @@ namespace NMS.AMQP.Test.Integration
                 Assert.True(latch.WaitOne(TimeSpan.FromMilliseconds(3000)), "Messages not received within given timeout.");
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestRecoveredMessageShouldNotBeMutated()
+        public async Task TestRecoveredMessageShouldNotBeMutated()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = EstablishConnection(testPeer);
-                connection.Start();
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
 
                 testPeer.ExpectBegin();
-                ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
-                IQueue destination = session.GetQueue("myQueue");
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.ClientAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
                 string originalPayload = "testMessage";
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message { BodySection = new AmqpValue() { Value = originalPayload } }, count: 1);
 
-                IMessageConsumer consumer = session.CreateConsumer(destination);
-                NmsTextMessage message = consumer.Receive() as NmsTextMessage;
+                IMessageConsumer consumer = await session.CreateConsumerAsync(destination);
+                NmsTextMessage message = await consumer.ReceiveAsync() as NmsTextMessage;
                 Assert.NotNull(message);
                 message.IsReadOnlyBody = false;
                 message.Text = message.Text + "Received";
-                session.Recover();
+                await session.RecoverAsync();
 
-                ITextMessage recoveredMessage = consumer.Receive() as ITextMessage;
+                ITextMessage recoveredMessage = await consumer.ReceiveAsync() as ITextMessage;
                 Assert.IsNotNull(recoveredMessage);
                 Assert.AreNotEqual(message.Text, recoveredMessage.Text);
                 Assert.AreEqual(originalPayload, recoveredMessage.Text);
                 Assert.AreNotSame(message, recoveredMessage);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/FailoverIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/FailoverIntegrationTest.cs
new file mode 100644
index 0000000..74f66ad
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/FailoverIntegrationTest.cs
@@ -0,0 +1,1164 @@
+/*
+ * 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 System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Amqp.Framing;
+using Amqp.Types;
+using Apache.NMS;
+using Apache.NMS.AMQP;
+using Moq;
+using NLog;
+using NMS.AMQP.Test.TestAmqp;
+using NMS.AMQP.Test.TestAmqp.BasicTypes;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class FailoverIntegrationTestAsync : IntegrationTestFixture
+    {
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+        
+        [Test, Timeout(20_000), Category("Windows")]
+        public async Task TestFailoverHandlesDropThenRejectionCloseAfterConnect()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer rejectingPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to, one to fail to reconnect to, and a final one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var rejectingUri = CreatePeerUri(rejectingPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+                
+                Logger.Info($"Original peer is at: {originalUri}");
+                Logger.Info($"Rejecting peer is at: {rejectingUri}");
+                Logger.Info($"Final peer is at: {finalUri}");
+
+                // Connect to the first
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+
+                long ird = 0;
+                long rd = 2000;
+
+                NmsConnection connection = await EstablishAnonymousConnection("failover.initialReconnectDelay=" + ird + "&failover.reconnectDelay=" + rd + "&failover.maxReconnectAttempts=10", originalPeer,
+                    rejectingPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+                Assert.False(finalConnected.WaitOne(TimeSpan.FromMilliseconds(100)), "Should not yet have connected to final peer");
+
+                // Set expectations on rejecting and final peer
+                rejectingPeer.RejectConnect(AmqpError.NOT_FOUND, "Resource could not be located");
+
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+
+                // Close the original peer and wait for things to shake out.
+                originalPeer.Close(sendClose: true);
+
+                rejectingPeer.WaitForAllMatchersToComplete(2000);
+
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(10)), "Should connect to final peer");
+
+                finalPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverHandlesDropWithModifiedInitialReconnectDelay()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to, then one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+                originalPeer.DropAfterLastMatcher();
+
+                NmsConnection connection = await EstablishAnonymousConnection("failover.initialReconnectDelay=1&failover.reconnectDelay=600&failover.maxReconnectAttempts=10", originalPeer, finalPeer);
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+
+                // Post Failover Expectations of FinalPeer
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+
+                await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to final peer");
+
+                // Shut it down
+                finalPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverInitialReconnectDelayDoesNotApplyToInitialConnect()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            {
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+
+                int delay = 20000;
+                Stopwatch watch = new Stopwatch();
+                watch.Start();
+
+                NmsConnection connection = await EstablishAnonymousConnection("failover.initialReconnectDelay=" + delay + "&failover.maxReconnectAttempts=1", originalPeer);
+                await connection.StartAsync();
+
+                watch.Stop();
+
+                Assert.True(watch.ElapsedMilliseconds < delay,
+                    "Initial connect should not have delayed for the specified initialReconnectDelay." + "Elapsed=" + watch.ElapsedMilliseconds + ", delay=" + delay);
+                Assert.True(watch.ElapsedMilliseconds < 5000, $"Connection took longer than reasonable: {watch.ElapsedMilliseconds}");
+
+                // Shut it down
+                originalPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                originalPeer.WaitForAllMatchersToComplete(2000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverHandlesDropAfterSessionCloseRequested()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to
+                var originalUri = CreatePeerUri(originalPeer);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer);
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to peer");
+
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectEnd(sendResponse: false);
+                originalPeer.DropAfterLastMatcher();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                ManualResetEvent sessionCloseCompleted = new ManualResetEvent(false);
+                Exception sessionClosedThrew = null;
+
+                Task.Run(() =>
+                {
+                    try
+                    {
+                        session.Close();
+                    }
+                    catch (Exception e)
+                    {
+                        sessionClosedThrew = e;
+                    }
+                    finally
+                    {
+                        sessionCloseCompleted.Set();
+                    }
+                });
+
+                originalPeer.WaitForAllMatchersToComplete(2000);
+
+                Assert.IsTrue(sessionCloseCompleted.WaitOne(TimeSpan.FromSeconds(3)), "Session close should have completed by now");
+                Assert.IsNull(sessionClosedThrew, "Session close should have completed normally");
+
+                await connection.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerFailsWhenLinkRefused()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+
+                NmsConnection connection = await EstablishAnonymousConnection(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                string topicName = "myTopic";
+                ITopic topic = await session.GetTopicAsync(topicName);
+
+                // Expect a link to a topic node, which we will then refuse
+                testPeer.ExpectReceiverAttach(sourceMatcher: source =>
+                {
+                    Assert.AreEqual(topicName, source.Address);
+                    Assert.IsFalse(source.Dynamic);
+                    Assert.AreEqual((uint) TerminusDurability.NONE, source.Durable);
+                }, targetMatcher: Assert.NotNull, linkNameMatcher: Assert.NotNull, refuseLink: true);
+
+                //Expect the detach response to the test peer closing the consumer link after refusal.
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: false, replyClosed: false);
+
+                Assert.CatchAsync<NMSException>(async () => await session.CreateConsumerAsync(topic));
+
+                // Shut it down
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverEnforcesRequestTimeoutSession()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent connected = new ManualResetEvent(false);
+                ManualResetEvent disconnected = new ManualResetEvent(false);
+
+                // Connect to the test peer
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+                testPeer.DropAfterLastMatcher(delay: 10);
+
+                NmsConnection connection = await EstablishAnonymousConnection("nms.requestTimeout=1000&failover.reconnectDelay=2000&failover.maxReconnectAttempts=60", testPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionInterrupted(It.IsAny<Uri>()))
+                    .Callback(() => { disconnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.IsAny<Uri>()))
+                    .Callback(() => { connected.Set(); });
+
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(connected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to peer");
+                Assert.True(disconnected.WaitOne(TimeSpan.FromSeconds(5)), "Should lose connection to peer");
+
+                Assert.CatchAsync<NMSException>(async () => await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge));
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverEnforcesSendTimeout()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent connected = new ManualResetEvent(false);
+                ManualResetEvent disconnected = new ManualResetEvent(false);
+
+                // Connect to the test peer
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+                testPeer.DropAfterLastMatcher();
+
+                NmsConnection connection = await EstablishAnonymousConnection("nms.sendTimeout=1000&failover.reconnectDelay=2000&failover.maxReconnectAttempts=60", testPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.IsAny<Uri>()))
+                    .Callback(() => { connected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionInterrupted(It.IsAny<Uri>()))
+                    .Callback(() => { disconnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(connected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to peer");
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                Assert.True(disconnected.WaitOne(TimeSpan.FromSeconds(5)), "Should lose connection to peer");
+
+                Assert.CatchAsync<NMSException>(async () => await producer.SendAsync(producer.CreateTextMessage("test")));
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverPassthroughOfCompletedSyncSend()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                NmsConnection connection = await EstablishAnonymousConnection((testPeer));
+
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Do a warm up
+                string messageContent1 = "myMessage1";
+                testPeer.ExpectTransfer(messageMatcher: m => { Assert.AreEqual(messageContent1, (m.BodySection as AmqpValue).Value); });
+
+                ITextMessage message1 = await session.CreateTextMessageAsync(messageContent1);
+                await producer.SendAsync(message1);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                // Create and send a new message, which is accepted
+                String messageContent2 = "myMessage2";
+                int delay = 15;
+                testPeer.ExpectTransfer(messageMatcher: m => Assert.AreEqual(messageContent2, (m.BodySection as AmqpValue).Value),
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    stateMatcher: Assert.IsNull,
+                    dispositionDelay: delay);
+                testPeer.ExpectClose();
+
+                ITextMessage message2 = await session.CreateTextMessageAsync(messageContent2);
+
+                DateTime start = DateTime.UtcNow;
+                await producer.SendAsync(message2);
+
+                TimeSpan elapsed = DateTime.UtcNow - start;
+                Assert.That(elapsed.TotalMilliseconds, Is.GreaterThanOrEqualTo(delay));
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverPassthroughOfRejectedSyncSend()
+        {
+            await DoFailoverPassthroughOfFailingSyncSendTestImpl(new Rejected());
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverPassthroughOfReleasedSyncSend()
+        {
+            await DoFailoverPassthroughOfFailingSyncSendTestImpl(new Released());
+        }
+
+        [Test, Timeout(20_000), Ignore("TODO: It should be fixed.")]
+        public async Task TestFailoverPassthroughOfModifiedFailedSyncSend()
+        {
+            var modified = new Modified()
+            {
+                DeliveryFailed = true
+            };
+            await DoFailoverPassthroughOfFailingSyncSendTestImpl(modified);
+        }
+
+        private async Task DoFailoverPassthroughOfFailingSyncSendTestImpl(Outcome failingState)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                NmsConnection connection = await EstablishAnonymousConnection((testPeer));
+
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Do a warm up that succeeds
+                string messageContent1 = "myMessage1";
+                testPeer.ExpectTransfer(messageMatcher: m => { Assert.AreEqual(messageContent1, (m.BodySection as AmqpValue).Value); });
+
+                ITextMessage message1 = await session.CreateTextMessageAsync(messageContent1);
+                await producer.SendAsync(message1);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                // Create and send a new message, which fails as it is not accepted
+                Assert.False(failingState is Accepted);
+
+                String messageContent2 = "myMessage2";
+                int delay = 15;
+                testPeer.ExpectTransfer(messageMatcher: m => Assert.AreEqual(messageContent2, (m.BodySection as AmqpValue).Value),
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: failingState,
+                    responseSettled: true,
+                    stateMatcher: Assert.IsNull,
+                    dispositionDelay: delay);
+
+                ITextMessage message2 = await session.CreateTextMessageAsync(messageContent2);
+
+                DateTime start = DateTime.UtcNow;
+                Assert.Catch(() => producer.Send(message2), "Expected an exception for this send.");
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                //Do a final send that succeeds
+                string messageContent3 = "myMessage3";
+                testPeer.ExpectTransfer(messageMatcher: m => { Assert.AreEqual(messageContent3, (m.BodySection as AmqpValue).Value); });
+
+                ITextMessage message3 = await session.CreateTextMessageAsync(messageContent3);
+                await producer.SendAsync(message3);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateSessionAfterConnectionDrops()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to, then one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin(sendResponse: false);
+                originalPeer.DropAfterLastMatcher();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+
+                // Post Failover Expectations of FinalPeer
+
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectEnd();
+                finalPeer.ExpectClose();
+
+                ISession session = await connection.CreateSessionAsync();
+
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to final peer");
+
+                await session.CloseAsync();
+                await connection.CloseAsync();
+
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerAfterConnectionDrops()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to, then one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+                originalPeer.DropAfterLastMatcher();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+
+                // Post Failover Expectations of FinalPeer
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectReceiverAttach();
+                finalPeer.ExpectLinkFlow(drain: false, sendDrainFlowResponse: false, creditMatcher: credit => Assert.AreEqual(credit, 200));
+                finalPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                finalPeer.ExpectClose();
+
+                ISession session = await connection.CreateSessionAsync();
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+
+                Assert.IsNull(await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(500)));
+
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to final peer");
+
+                await consumer.CloseAsync();
+
+                // Shut it down
+                await connection.CloseAsync();
+
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateProducerAfterConnectionDrops()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Create a peer to connect to, then one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+                originalPeer.DropAfterLastMatcher();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+
+                // Post Failover Expectations of FinalPeer
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectSenderAttach();
+                finalPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                finalPeer.ExpectClose();
+
+                ISession session = await connection.CreateSessionAsync();
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to final peer");
+
+                await producer.CloseAsync();
+
+                await connection.CloseAsync();
+
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000), Ignore("TODO: Fix")]
+        public async Task TestStartMaxReconnectAttemptsTriggeredWhenRemotesAreRejecting()
+        {
+            using (TestAmqpPeer firstPeer = new TestAmqpPeer())
+            using (TestAmqpPeer secondPeer = new TestAmqpPeer())
+            using (TestAmqpPeer thirdPeer = new TestAmqpPeer())
+            using (TestAmqpPeer fourthPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent failedConnection = new ManualResetEvent(false);
+
+                firstPeer.RejectConnect(AmqpError.NOT_FOUND, "Resource could not be located");
+                secondPeer.RejectConnect(AmqpError.NOT_FOUND, "Resource could not be located");
+                thirdPeer.RejectConnect(AmqpError.NOT_FOUND, "Resource could not be located");
+
+                // This shouldn't get hit, but if it does accept the connect so we don't pass the failed
+                // to connect assertion.
+                fourthPeer.ExpectSaslAnonymous();
+                fourthPeer.ExpectOpen();
+                fourthPeer.ExpectBegin();
+                fourthPeer.ExpectClose();
+
+                NmsConnection connection = await EstablishAnonymousConnection("failover.startupMaxReconnectAttempts=3&failover.reconnectDelay=15&failover.useReconnectBackOff=false",
+                    firstPeer, secondPeer, thirdPeer, fourthPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionFailure(It.IsAny<NMSException>()))
+                    .Callback(() => { failedConnection.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                Assert.CatchAsync<NMSException>(async () => await connection.StartAsync(), "Should not be able to connect");
+
+                Assert.True(failedConnection.WaitOne(TimeSpan.FromSeconds(5)));
+
+                try
+                {
+                    await connection.CloseAsync();
+                }
+                catch (NMSException e)
+                {
+                }
+                
+                firstPeer.WaitForAllMatchersToComplete(2000);
+                secondPeer.WaitForAllMatchersToComplete(2000);
+                thirdPeer.WaitForAllMatchersToComplete(2000);
+                
+                // Shut down last peer and verify no connection made to it
+                fourthPeer.PurgeExpectations();
+                fourthPeer.Close();
+                Assert.NotNull(firstPeer.ClientSocket, "Peer 1 should have accepted a TCP connection");
+                Assert.NotNull(secondPeer.ClientSocket, "Peer 2 should have accepted a TCP connection");
+                Assert.NotNull(thirdPeer.ClientSocket, "Peer 3 should have accepted a TCP connection");
+                Assert.IsNull(fourthPeer.ClientSocket, "Peer 4 should not have accepted any TCP connection");
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyCloseConsumerWithMessageListenerFiresNMSExceptionListener()
+        {
+            Symbol errorCondition = AmqpError.RESOURCE_DELETED;
+            string errorDescription = nameof(TestRemotelyCloseConsumerWithMessageListenerFiresNMSExceptionListener);
+            
+            await DoRemotelyCloseConsumerWithMessageListenerFiresNMSExceptionListenerTestImpl(errorCondition, errorDescription);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyCloseConsumerWithMessageListenerWithoutErrorFiresNMSExceptionListener()
+        {
+            await DoRemotelyCloseConsumerWithMessageListenerFiresNMSExceptionListenerTestImpl(null, null);
+        }
+
+        private async Task DoRemotelyCloseConsumerWithMessageListenerFiresNMSExceptionListenerTestImpl(Symbol errorType, string errorMessage)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent consumerClosed = new ManualResetEvent(false);
+                ManualResetEvent exceptionListenerFired = new ManualResetEvent(false);
+                
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+                
+                NmsConnection connection = await EstablishAnonymousConnection("failover.maxReconnectAttempts=1", testPeer);
+                
+                connection.ExceptionListener += exception => { exceptionListenerFired.Set(); };
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConsumerClosed(It.IsAny<IMessageConsumer>(), It.IsAny<Exception>()))
+                    .Callback(() => { consumerClosed.Set(); });
+                
+                connection.AddConnectionListener(connectionListener.Object);
+                
+                testPeer.ExpectBegin();
+                testPeer.ExpectBegin();
+
+                ISession session1 = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                ISession session2 = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session2.GetQueueAsync("myQueue");
+                
+                // Create a consumer, then remotely end it afterwards.
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectEnd();
+                testPeer.RemotelyDetachLastOpenedLinkOnLastOpenedSession(expectDetachResponse: true, closed: true,  errorType: errorType, errorMessage: errorMessage, delayBeforeSend: 10);
+
+                IMessageConsumer consumer = await session2.CreateConsumerAsync(queue);
+                consumer.Listener += message => { };
+                
+                // Close first session to allow the receiver remote close timing to be deterministic
+                await session1.CloseAsync();
+                
+                // Verify the consumer gets marked closed
+                testPeer.WaitForAllMatchersToComplete(1000);
+                
+                Assert.True(consumerClosed.WaitOne(TimeSpan.FromMilliseconds(2000)), "Consumer closed callback didn't trigger");
+                Assert.True(exceptionListenerFired.WaitOne(TimeSpan.FromMilliseconds(2000)), "NMS Exception listener should have fired with a MessageListener");
+                
+                // Try closing it explicitly, should effectively no-op in client.
+                // The test peer will throw during close if it sends anything.
+                await consumer.CloseAsync();
+                
+                // Shut the connection down
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestFailoverDoesNotFailPendingSend()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+                
+                // Ensure our send blocks in the provider waiting for credit so that on failover
+                // the message will actually get sent from the Failover bits once we grant some
+                // credit for the recovered sender.
+                originalPeer.ExpectSenderAttachWithoutGrantingCredit();
+                originalPeer.DropAfterLastMatcher(delay: 10); // Wait for sender to get into wait state
+                
+                // Post Failover Expectations of sender
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectSenderAttach();
+                finalPeer.ExpectTransfer(messageMatcher: Assert.IsNotNull);
+                finalPeer.ExpectClose();
+                
+                NmsConnection connection = await EstablishAnonymousConnection("failover.initialReconnectDelay=25", originalPeer, finalPeer);
+                ISession session = await connection.CreateSessionAsync();
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+                
+                // Create and transfer a new message
+                string text = "myMessage";
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                
+                Assert.DoesNotThrow(() =>
+                {
+                    producer.Send(message);
+                });
+                
+                await connection.CloseAsync();
+                
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestTempDestinationRecreatedAfterConnectionFailsOver()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+                
+                // Create a peer to connect to, then one to reconnect to
+                var originalUri = CreatePeerUri(originalPeer);
+                var finalUri = CreatePeerUri(finalPeer);
+                
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+                string dynamicAddress1 = "myTempTopicAddress";
+                originalPeer.ExpectTempTopicCreationAttach(dynamicAddress1);
+                originalPeer.DropAfterLastMatcher();
+                
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.Is<Uri>(uri => originalUri == uri.ToString())))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.Is<Uri>(uri => finalUri == uri.ToString())))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+                
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+                
+                // Post Failover Expectations of FinalPeer
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                String dynamicAddress2 = "myTempTopicAddress2";
+                finalPeer.ExpectTempTopicCreationAttach(dynamicAddress2);
+                
+                // Session is recreated after previous temporary destinations are recreated on failover.
+                finalPeer.ExpectBegin();
+                
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                ITemporaryTopic temporaryTopic = await session.CreateTemporaryTopicAsync();
+                
+                Assert.True(finalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to final peer");
+                
+                // Delete the temporary Topic and close the session.
+                finalPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                finalPeer.ExpectEnd();
+                
+                await temporaryTopic.DeleteAsync();
+                
+                await session.CloseAsync();
+                
+                // Shut it down
+                finalPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                originalPeer.WaitForAllMatchersToComplete(2000);
+                finalPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestConsumerCanReceivesMessagesWhenConnectionLostDuringAutoAck()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent consumerReady = new ManualResetEvent(false);
+                ManualResetEvent originalConnected = new ManualResetEvent(false);
+                ManualResetEvent finalConnected = new ManualResetEvent(false);
+
+                // Connect to the first peer
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                Mock<INmsConnectionListener> connectionListener = new Mock<INmsConnectionListener>();
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionEstablished(It.IsAny<Uri>()))
+                    .Callback(() => { originalConnected.Set(); });
+
+                connectionListener
+                    .Setup(listener => listener.OnConnectionRestored(It.IsAny<Uri>()))
+                    .Callback(() => { finalConnected.Set(); });
+
+                connection.AddConnectionListener(connectionListener.Object);
+
+                await connection.StartAsync();
+
+                Assert.True(originalConnected.WaitOne(TimeSpan.FromSeconds(5)), "Should connect to original peer");
+
+                originalPeer.ExpectReceiverAttach();
+                originalPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
+                originalPeer.RunAfterLastHandler(() => consumerReady.WaitOne(TimeSpan.FromSeconds(2)));
+                originalPeer.DropAfterLastMatcher();
+
+                // Post Failover Expectations of FinalPeer
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectReceiverAttach();
+                finalPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
+                finalPeer.ExpectDispositionThatIsAcceptedAndSettled();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageConsumer messageConsumer = await session.CreateConsumerAsync(queue);
+                CountdownEvent msgReceivedLatch = new CountdownEvent(2);
+                messageConsumer.Listener += message =>
+                {
+                    if (msgReceivedLatch.CurrentCount == 2)
+                    {
+                        consumerReady.Set();
+                        finalConnected.WaitOne(2000);
+                    }
+
+                    msgReceivedLatch.Signal();
+                };
+
+                finalPeer.WaitForAllMatchersToComplete(5000);
+
+                Assert.IsTrue(msgReceivedLatch.Wait(TimeSpan.FromSeconds(10)), $"Expected 2 messages, but got {2 - msgReceivedLatch.CurrentCount}");
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateProducerFailsWhenLinkRefused()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                testPeer.ExpectSaslAnonymous();
+                testPeer.ExpectOpen();
+                testPeer.ExpectBegin();
+
+                NmsConnection connection = await EstablishAnonymousConnection(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                string topicName = "myTopic";
+                ITopic topic = await session.GetTopicAsync(topicName);
+
+                // Expect a link to a topic node, which we will then refuse
+                testPeer.ExpectSenderAttach(targetMatcher: x =>
+                {
+                    Target target = (Target) x;
+
+                    Assert.AreEqual(topicName, target.Address);
+                    Assert.IsFalse(target.Dynamic);
+                    Assert.AreEqual((uint) TerminusDurability.NONE, target.Durable);
+                }, sourceMatcher: Assert.NotNull, refuseLink: true);
+
+                //Expect the detach response to the test peer closing the producer link after refusal.
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: false, replyClosed: false);
+
+                Assert.CatchAsync<NMSException>(async () => await session.CreateProducerAsync(topic));
+
+                // Shut it down
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000), Category("Windows")]
+        public async Task TestConnectionInterruptedInvokedWhenConnectionToBrokerLost()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent connectionInterruptedInvoked = new ManualResetEvent(false);
+
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer);
+
+                connection.ConnectionInterruptedListener += () => connectionInterruptedInvoked.Set();
+
+                await connection.StartAsync();
+                
+                originalPeer.Close();
+
+                Assert.IsTrue(connectionInterruptedInvoked.WaitOne(TimeSpan.FromSeconds(10)));
+            }
+        }
+        
+        [Test, Timeout(20_000), Category("Windows")]
+        public async Task TestConnectionResumedInvokedWhenConnectionToBrokerLost()
+        {
+            using (TestAmqpPeer originalPeer = new TestAmqpPeer())
+            using (TestAmqpPeer finalPeer = new TestAmqpPeer())
+            {
+                ManualResetEvent connectionResumedInvoked = new ManualResetEvent(false);
+
+                originalPeer.ExpectSaslAnonymous();
+                originalPeer.ExpectOpen();
+                originalPeer.ExpectBegin();
+                originalPeer.ExpectBegin();
+
+                finalPeer.ExpectSaslAnonymous();
+                finalPeer.ExpectOpen();
+                finalPeer.ExpectBegin();
+                finalPeer.ExpectBegin();
+
+                NmsConnection connection = await EstablishAnonymousConnection(originalPeer, finalPeer);
+
+                connection.ConnectionResumedListener += () => connectionResumedInvoked.Set();
+
+                await connection.StartAsync();
+                
+                originalPeer.Close();
+                Assert.IsTrue(connectionResumedInvoked.WaitOne(TimeSpan.FromSeconds(10)));
+            }
+        }
+
+        private Task<NmsConnection> EstablishAnonymousConnection(params TestAmqpPeer[] peers)
+        {
+            return EstablishAnonymousConnection(null, null, peers);
+        }
+
+        private Task<NmsConnection> EstablishAnonymousConnection(string failoverParams, params TestAmqpPeer[] peers)
+        {
+            return EstablishAnonymousConnection(null, failoverParams, peers);
+        }
+
+        private async Task<NmsConnection> EstablishAnonymousConnection(string connectionParams, string failoverParams, params TestAmqpPeer[] peers)
+        {
+            if (peers.Length == 0)
+            {
+                throw new ArgumentException("No test peers were given, at least 1 required");
+            }
+
+            string remoteUri = "failover:(";
+            bool first = true;
+            foreach (TestAmqpPeer peer in peers)
+            {
+                if (!first)
+                {
+                    remoteUri += ",";
+                }
+
+                remoteUri += CreatePeerUri(peer, connectionParams);
+                first = false;
+            }
+
+            if (failoverParams == null)
+            {
+                remoteUri += ")?failover.maxReconnectAttempts=10";
+            }
+            else
+            {
+                remoteUri += ")?" + failoverParams;
+            }
+
+            NmsConnectionFactory factory = new NmsConnectionFactory(remoteUri);
+            return (NmsConnection) await factory.CreateConnectionAsync();
+        }
+
+        private string CreatePeerUri(TestAmqpPeer peer, string parameters = null)
+        {
+            return $"amqp://127.0.0.1:{peer.ServerPort}/{(parameters != null ? "?" + parameters : "")}";
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/MessageDeliveryTimeTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/MessageDeliveryTimeTest.cs
similarity index 64%
copy from test/Apache-NMS-AMQP-Test/Integration/MessageDeliveryTimeTest.cs
copy to test/Apache-NMS-AMQP-Test/Integration/Async/MessageDeliveryTimeTest.cs
index dbe936a..157b159 100644
--- a/test/Apache-NMS-AMQP-Test/Integration/MessageDeliveryTimeTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/MessageDeliveryTimeTest.cs
@@ -16,6 +16,7 @@
  */
 
 using System;
+using System.Threading.Tasks;
 using Amqp.Framing;
 using Amqp.Types;
 using Apache.NMS;
@@ -23,50 +24,50 @@ using Apache.NMS.AMQP.Util;
 using NMS.AMQP.Test.TestAmqp;
 using NUnit.Framework;
 
-namespace NMS.AMQP.Test.Integration
+namespace NMS.AMQP.Test.Integration.Async
 {
     [TestFixture]
-    public class MessageDeliveryTimeTest : IntegrationTestFixture
+    public class MessageDeliveryTimeTestAsync : IntegrationTestFixture
     {
         [Test, Timeout(20000)]
-        public void TestReceiveMessageWithoutDeliveryTimeSet()
+        public async Task TestReceiveMessageWithoutDeliveryTimeSet()
         {
-            DoReceiveMessageDeliveryTime(null, null);
+            await DoReceiveMessageDeliveryTime(null, null);
         }
 
         [Test, Timeout(20000)]
-        public void TestDeliveryTimeIsDateTime()
+        public async Task TestDeliveryTimeIsDateTime()
         {
             DateTime deliveryTime = DateTimeOffset.FromUnixTimeMilliseconds(CurrentTimeInMillis() + 12345).DateTime.ToUniversalTime();
-            DoReceiveMessageDeliveryTime(deliveryTime, deliveryTime);
+            await DoReceiveMessageDeliveryTime(deliveryTime, deliveryTime);
         }
 
         [Test, Timeout(20000)]
-        public void TestDeliveryTimeIsULong()
+        public async Task TestDeliveryTimeIsULong()
         {
             ulong deliveryTime = (ulong) (CurrentTimeInMillis() + 12345);
-            DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds((long) deliveryTime).DateTime);
+            await DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds((long) deliveryTime).DateTime);
         }
 
         [Test, Timeout(20000)]
-        public void TestDeliveryTimeIsLong()
+        public async Task TestDeliveryTimeIsLong()
         {
             long deliveryTime = (CurrentTimeInMillis() + 12345);
-            DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
+            await DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
         }
 
         [Test, Timeout(20000)]
-        public void TestDeliveryTimeIsInt()
+        public async Task TestDeliveryTimeIsInt()
         {
             int deliveryTime = (int) (CurrentTimeInMillis() + 12345);
-            DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
+            await DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
         }
 
         [Test, Timeout(20000)]
-        public void TestDeliveryTimeIsUInt()
+        public async Task TestDeliveryTimeIsUInt()
         {
             uint deliveryTime = (uint) (CurrentTimeInMillis() + 12345);
-            DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
+            await DoReceiveMessageDeliveryTime(deliveryTime, DateTimeOffset.FromUnixTimeMilliseconds(deliveryTime).DateTime);
         }
 
         private long CurrentTimeInMillis()
@@ -74,15 +75,15 @@ namespace NMS.AMQP.Test.Integration
             return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
         }
 
-        private void DoReceiveMessageDeliveryTime(object setDeliveryTimeAnnotation, DateTime? expectedDeliveryTime)
+        private async Task DoReceiveMessageDeliveryTime(object setDeliveryTimeAnnotation, DateTime? expectedDeliveryTime)
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var connection = EstablishConnection(testPeer, "amqp.traceFrames=true");
-                connection.Start();
+                var connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
                 testPeer.ExpectBegin();
-                var session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                var queue = session.GetQueue("myQueue");
+                var session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                var queue = await session.GetQueueAsync("myQueue");
 
                 var message = CreateMessageWithNullContent();
                 if (setDeliveryTimeAnnotation != null)
@@ -96,14 +97,14 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.ExpectDisposition(true, (deliveryState) => { });
 
                 DateTime startingTimeFrom = DateTime.UtcNow;
-                var messageConsumer = session.CreateConsumer(queue);
-                var receivedMessage = messageConsumer.Receive(TimeSpan.FromMilliseconds(3000));
+                var messageConsumer = await session.CreateConsumerAsync(queue);
+                var receivedMessage = await messageConsumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000));
                 DateTime receivingTime = DateTime.UtcNow;
 
                 testPeer.WaitForAllMatchersToComplete(3000);
 
                 testPeer.ExpectClose();
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(3000);
 
@@ -121,23 +122,23 @@ namespace NMS.AMQP.Test.Integration
         }
 
         [Test, Timeout(20_000)]
-        public void TestDeliveryDelayNotSupportedThrowsException()
+        public async Task TestDeliveryDelayNotSupportedThrowsException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                IConnection connection = base.EstablishConnection(testPeer);
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
                 testPeer.ExpectBegin();
                 testPeer.ExpectSenderAttach();
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
-                IMessageProducer producer = session.CreateProducer(queue);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
                 Assert.Throws<NotSupportedException>(() => producer.DeliveryDelay = TimeSpan.FromMinutes(17));
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestDeliveryDelayHasItsReflectionInAmqpAnnotations()
+        public async Task TestDeliveryDelayHasItsReflectionInAmqpAnnotations()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
@@ -146,15 +147,15 @@ namespace NMS.AMQP.Test.Integration
                 long currentUnixEpochTime = new DateTimeOffset(DateTime.UtcNow + deliveryDelay).ToUnixTimeMilliseconds();
                 long currentUnixEpochTime2 = new DateTimeOffset(DateTime.UtcNow + deliveryDelay + deliveryDelay).ToUnixTimeMilliseconds();
 
-                IConnection connection = base.EstablishConnection(testPeer,
+                IConnection connection = await base.EstablishConnectionAsync(testPeer,
                     serverCapabilities: new Symbol[] {SymbolUtil.OPEN_CAPABILITY_DELAYED_DELIVERY, SymbolUtil.OPEN_CAPABILITY_SOLE_CONNECTION_FOR_CONTAINER});
                 testPeer.ExpectBegin();
                 testPeer.ExpectSenderAttach();
 
 
-                ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
-                IQueue queue = session.GetQueue("myQueue");
-                IMessageProducer producer = session.CreateProducer(queue);
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
                 producer.DeliveryDelay = deliveryDelay;
 
                 // Create and transfer a new message
@@ -167,12 +168,12 @@ namespace NMS.AMQP.Test.Integration
                 });
                 testPeer.ExpectClose();
 
-                ITextMessage textMessage = session.CreateTextMessage();
+                ITextMessage textMessage = await session.CreateTextMessageAsync();
 
-                producer.Send(textMessage);
+                await producer.SendAsync(textMessage);
                 Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
 
-                connection.Close();
+                await connection.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(1000);
             }
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/MessageExpirationIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/MessageExpirationIntegrationTest.cs
new file mode 100644
index 0000000..427acdd
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/MessageExpirationIntegrationTest.cs
@@ -0,0 +1,252 @@
+/*
+ * 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 System.Threading;
+using System.Threading.Tasks;
+using Amqp.Framing;
+using Apache.NMS;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class MessageExpirationIntegrationTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestIncomingExpiredMessageGetsFiltered()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                // Expected the consumer to attach and send credit, then send it an
+                // already-expired message followed by a live message.
+                testPeer.ExpectReceiverAttach();
+                string expiredMsgContent = "already-expired";
+                Amqp.Message message = CreateExpiredMessage(expiredMsgContent);
+                testPeer.ExpectLinkFlowRespondWithTransfer(message: message);
+
+                string liveMsgContent = "valid";
+                testPeer.SendTransferToLastOpenedLinkOnLastOpenedSession(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = liveMsgContent } }, nextIncomingId: 2);
+
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+
+                // Call receive, expect the first message to be filtered due to expiry,
+                // and the second message to be given to the test app and accepted.
+                Action<DeliveryState> modifiedMatcher = state =>
+                {
+                    var modified = state as Modified;
+                    Assert.IsNotNull(modified);
+                    Assert.IsTrue(modified.DeliveryFailed);
+                    Assert.IsTrue(modified.UndeliverableHere);
+                };
+                testPeer.ExpectDisposition(settled: true, stateMatcher: modifiedMatcher, firstDeliveryId: 1, lastDeliveryId: 1);
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId: 2, lastDeliveryId: 2);
+
+                IMessage m = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000));
+                Assert.NotNull(m, "Message should have been received");
+                Assert.IsInstanceOf<ITextMessage>(m);
+                Assert.AreEqual(liveMsgContent, (m as ITextMessage).Text, "Unexpected message content");
+
+                // Verify the other message is not there. Will drain to be sure there are no messages.
+                Assert.IsNull(await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(10)), "Message should not have been received");
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(3000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestIncomingExpiredMessageGetsConsumedWhenFilterDisabled()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer, "?nms.localMessageExpiry=false");
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                // Expected the consumer to attach and send credit, then send it an
+                // already-expired message followed by a live message.
+                testPeer.ExpectReceiverAttach();
+
+                string expiredMsgContent = "already-expired";
+                Amqp.Message message = CreateExpiredMessage(expiredMsgContent);
+                testPeer.ExpectLinkFlowRespondWithTransfer(message: message);
+
+                string liveMsgContent = "valid";
+                testPeer.SendTransferToLastOpenedLinkOnLastOpenedSession(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = liveMsgContent } }, nextIncomingId: 2);
+
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+
+                // Call receive, expect the expired message as we disabled local expiry.
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId: 1, lastDeliveryId: 1);
+
+                IMessage m = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000));
+                Assert.NotNull(m, "Message should have been received");
+                Assert.IsInstanceOf<ITextMessage>(m);
+                Assert.AreEqual(expiredMsgContent, ((ITextMessage) m).Text, "Unexpected message content");
+
+                // Verify the other message is there
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId: 2, lastDeliveryId: 2);
+
+                m = await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(3000));
+                Assert.NotNull(m, "Message should have been received");
+                Assert.IsInstanceOf<ITextMessage>(m);
+                Assert.AreEqual(liveMsgContent, ((ITextMessage) m).Text, "Unexpected message content");
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(3000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestIncomingExpiredMessageGetsFilteredAsync()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                // Expected the consumer to attach and send credit, then send it an
+                // already-expired message followed by a live message.
+                testPeer.ExpectReceiverAttach();
+
+                string expiredMsgContent = "already-expired";
+                Amqp.Message message = CreateExpiredMessage(expiredMsgContent);
+                testPeer.ExpectLinkFlowRespondWithTransfer(message: message);
+
+                string liveMsgContent = "valid";
+                testPeer.SendTransferToLastOpenedLinkOnLastOpenedSession(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = liveMsgContent } }, nextIncomingId: 2);
+
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+
+                // Add message listener, expect the first message to be filtered due to expiry,
+                // and the second message to be given to the test app and accepted.
+                Action<DeliveryState> modifiedMatcher = state =>
+                {
+                    var modified = state as Modified;
+                    Assert.IsNotNull(modified);
+                    Assert.IsTrue(modified.DeliveryFailed);
+                    Assert.IsTrue(modified.UndeliverableHere);
+                };
+                testPeer.ExpectDisposition(settled: true, stateMatcher: modifiedMatcher, firstDeliveryId: 1, lastDeliveryId: 1);
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId: 2, lastDeliveryId: 2);
+
+
+                ManualResetEvent success = new ManualResetEvent(false);
+                ManualResetEvent listenerFailure = new ManualResetEvent(false);
+
+                consumer.Listener += m =>
+                {
+                    if (liveMsgContent.Equals(((ITextMessage) m).Text))
+                        success.Set();
+                    else
+                        listenerFailure.Set();
+                };
+
+                Assert.True(success.WaitOne(TimeSpan.FromSeconds(5)), "didn't get expected message");
+                Assert.False(listenerFailure.WaitOne(TimeSpan.FromMilliseconds(100)), "Received message when message should not have been received");
+
+                testPeer.WaitForAllMatchersToComplete(3000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(3000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestIncomingExpiredMessageGetsConsumedWhenFilterDisabledAsync()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer, "?nms.localMessageExpiry=false");
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                // Expected the consumer to attach and send credit, then send it an
+                // already-expired message followed by a live message.
+                testPeer.ExpectReceiverAttach();
+
+                string expiredMsgContent = "already-expired";
+                Amqp.Message message = CreateExpiredMessage(expiredMsgContent);
+                testPeer.ExpectLinkFlowRespondWithTransfer(message: message);
+
+                string liveMsgContent = "valid";
+                testPeer.SendTransferToLastOpenedLinkOnLastOpenedSession(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = liveMsgContent } }, nextIncomingId: 2);
+
+                IMessageConsumer consumer = await session.CreateConsumerAsync(queue);
+                
+                // Add message listener, expect both messages as the filter is disabled
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId:1, lastDeliveryId:1);
+                testPeer.ExpectDisposition(settled: true, stateMatcher: Assert.IsInstanceOf<Accepted>, firstDeliveryId:2, lastDeliveryId:2);
+
+                CountdownEvent success = new CountdownEvent(2);
+
+                consumer.Listener += m =>
+                {
+                    if (expiredMsgContent.Equals(((ITextMessage) m).Text) || liveMsgContent.Equals(((ITextMessage) m).Text))
+                        success.Signal();
+                };
+                
+                Assert.IsTrue(success.Wait(TimeSpan.FromSeconds(5)), "Didn't get expected messages");
+                
+                testPeer.WaitForAllMatchersToComplete(3000);
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(3000);
+            }
+        }
+
+        private static Amqp.Message CreateExpiredMessage(string value)
+        {
+            return new Amqp.Message
+            {
+                BodySection = new AmqpValue() { Value = value },
+                Properties = new Properties { AbsoluteExpiryTime = DateTime.UtcNow - TimeSpan.FromMilliseconds(100) }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/NMSConsumerIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSConsumerIntegrationTest.cs
similarity index 72%
copy from test/Apache-NMS-AMQP-Test/Integration/NMSConsumerIntegrationTest.cs
copy to test/Apache-NMS-AMQP-Test/Integration/Async/NMSConsumerIntegrationTest.cs
index c1bb33b..a27b268 100644
--- a/test/Apache-NMS-AMQP-Test/Integration/NMSConsumerIntegrationTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSConsumerIntegrationTest.cs
@@ -16,49 +16,51 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Amqp.Framing;
+using Amqp.Types;
 using Apache.NMS;
 using Apache.NMS.AMQP.Message;
 using Apache.NMS.AMQP.Util;
 using NMS.AMQP.Test.TestAmqp;
 using NUnit.Framework;
 
-namespace NMS.AMQP.Test.Integration
+namespace NMS.AMQP.Test.Integration.Async
 {
     // Adapted from ConsumerIntegrationTest to use NMSContext
     [TestFixture]
-    public class NMSConsumerIntegrationTest : IntegrationTestFixture
+    public class NMSConsumerIntegrationTestAsync : IntegrationTestFixture
     {
         [Test, Timeout(20_000)]
-        public void TestCloseConsumer()
+        public async Task TestCloseConsumer()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
+                var context = await EstablishNMSContextAsync(testPeer);
                 testPeer.ExpectBegin();
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
 
-                IQueue queue = context.GetQueue("myQueue");
-                var consumer = context.CreateConsumer(queue);
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                var consumer = await context.CreateConsumerAsync(queue);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(1000);
             }
         }
 
-        // TODO No connection Listener in context
+        // TODO No connection Listener in NMSContext
         // [Test, Timeout(20_000)]
-        // public void TestRemotelyCloseConsumer()
+        // public async Task TestRemotelyCloseConsumer()
         // {
         //     Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
         //     string errorMessage = "buba";
@@ -72,7 +74,7 @@ namespace NMS.AMQP.Test.Integration
         //             .Setup(listener => listener.OnConsumerClosed(It.IsAny<IMessageConsumer>(), It.IsAny<Exception>()))
         //             .Callback(() => consumerClosed.Set());
         //
-        //         var context = (NmsContext) EstablishNMSContext(testPeer, "amqp.traceFrames=true");
+        //         var context = (NmsContext) EstablishNMSContext(testPeer);
         //         context.ConnectionInterruptedListener += () => { consumerClosed.Set(); };// AddConnectionListener(mockConnectionListener.Object);}
         //         // context.list ConnectionInterruptedListener += () => { consumerClosed.Set(); };// AddConnectionListener(mockConnectionListener.Object);}
         //         context.ExceptionListener += exception => { exceptionFired.Set(); };
@@ -102,7 +104,7 @@ namespace NMS.AMQP.Test.Integration
         // }
 
         // [Test, Timeout(20_000)]
-        // public void TestRemotelyCloseConsumerWithMessageListenerFiresExceptionListener()
+        // public async Task TestRemotelyCloseConsumerWithMessageListenerFiresExceptionListener()
         // {
         //     Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
         //     string errorMessage = "buba";
@@ -146,135 +148,135 @@ namespace NMS.AMQP.Test.Integration
         // }
 
         [Test, Timeout(20_000)]
-        public void TestReceiveMessageWithReceiveZeroTimeout()
+        public async Task TestReceiveMessageWithReceiveZeroTimeout()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue queue = context.GetQueue("myQueue");
+                IQueue queue = await context.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
 
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = null } }, count: 1);
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
-                var consumer = context.CreateConsumer(queue);
-                IMessage message = consumer.Receive();
+                var consumer = await context.CreateConsumerAsync(queue);
+                IMessage message = await consumer.ReceiveAsync();
                 Assert.NotNull(message, "A message should have been received");
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(10000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestExceptionInOnMessageReleasesInAutoAckMode()
+        public async Task TestExceptionInOnMessageReleasesInAutoAckMode()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue queue = context.GetQueue("myQueue");
+                IQueue queue = await context.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message() { BodySection = new AmqpValue() { Value = null } }, count: 1);
                 testPeer.ExpectDispositionThatIsReleasedAndSettled();
 
-                var consumer = context.CreateConsumer(queue);
+                var consumer = await context.CreateConsumerAsync(queue);
                 consumer.Listener += message => throw new Exception();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(10000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestCloseDurableTopicSubscriberDetachesWithCloseFalse()
+        public async Task TestCloseDurableTopicSubscriberDetachesWithCloseFalse()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
                 
                 string topicName = "myTopic";
                 string subscriptionName = "mySubscription";
-                ITopic topic = context.GetTopic(topicName);
+                ITopic topic = await context.GetTopicAsync(topicName);
 
                 testPeer.ExpectDurableSubscriberAttach(topicName, subscriptionName);
                 testPeer.ExpectLinkFlow();
 
-                var durableConsumer = context.CreateDurableConsumer(topic, subscriptionName, null, false);
+                var durableConsumer = await context.CreateDurableConsumerAsync(topic, subscriptionName, null, false);
 
                 testPeer.ExpectDetach(expectClosed: false, sendResponse: true, replyClosed: false);
-                durableConsumer.Close();
+                await durableConsumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(1000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerReceiveThrowsIfConnectionLost()
+        public async Task TestConsumerReceiveThrowsIfConnectionLost()
         {
-            DoTestConsumerReceiveThrowsIfConnectionLost(false);
+            await DoTestConsumerReceiveThrowsIfConnectionLost(false);
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerTimedReceiveThrowsIfConnectionLost()
+        public async Task TestConsumerTimedReceiveThrowsIfConnectionLost()
         {
-            DoTestConsumerReceiveThrowsIfConnectionLost(true);
+            await DoTestConsumerReceiveThrowsIfConnectionLost(true);
         }
 
-        private void DoTestConsumerReceiveThrowsIfConnectionLost(bool useTimeout)
+        private async Task DoTestConsumerReceiveThrowsIfConnectionLost(bool useTimeout)
         {
             ManualResetEvent consumerReady = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
+                var context = await EstablishNMSContextAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                IQueue queue = context.GetQueue("queue");
-                context.Start();
+                IQueue queue = await context.GetQueueAsync("queue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
                 testPeer.RunAfterLastHandler(() => { consumerReady.WaitOne(2000); });
                 testPeer.DropAfterLastMatcher(delay: 10);
 
-                var consumer = context.CreateConsumer(queue);
+                var consumer = await context.CreateConsumerAsync(queue);
                 consumerReady.Set();
 
                 try
                 {
                     if (useTimeout)
                     {
-                        consumer.Receive(TimeSpan.FromMilliseconds(10_0000));
+                        await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(10_0000));
                     }
                     else
                     {
-                        consumer.Receive();
+                        await consumer.ReceiveAsync();
                     }
 
 
@@ -291,7 +293,7 @@ namespace NMS.AMQP.Test.Integration
 
         //  TODO No connection Listener in context
         // [Test, Timeout(20_000)]
-        // public void TestConsumerReceiveNoWaitThrowsIfConnectionLost()
+        // public async Task TestConsumerReceiveNoWaitThrowsIfConnectionLost()
         // {
         //     ManualResetEvent disconnected = new ManualResetEvent(false);
         //
@@ -333,23 +335,23 @@ namespace NMS.AMQP.Test.Integration
         // }
 
         [Test, Timeout(20_000)]
-        public void TestSetMessageListenerAfterStartAndSend()
+        public async Task TestSetMessageListenerAfterStartAndSend()
         {
             int messageCount = 4;
             CountdownEvent latch = new CountdownEvent(messageCount);
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), messageCount);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 for (int i = 0; i < messageCount; i++)
                 {
@@ -364,117 +366,58 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
 
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
-        // TODO Connection is started anyway when creating consumer
-        // [Test, Timeout(20_000)]
-        // public void TestNoReceivedMessagesWhenConnectionNotStarted()
-        // {
-        //     using (TestAmqpPeer testPeer = new TestAmqpPeer())
-        //     {
-        //         var context = EstablishNMSContext(testPeer);
-        //         
-        //         testPeer.ExpectBegin();
-        //
-        //         IQueue destination = context.GetQueue("myQueue");
-        //
-        //         testPeer.ExpectReceiverAttach();
-        //         testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 3);
-        //
-        //         // cREATING CONSUMER STARTS CONNECTION
-        //         var consumer = context.CreateConsumer(destination);
-        //
-        //         // Wait for a message to arrive then try and receive it, which should not happen
-        //         // since the connection is not started.
-        //         Assert.Null(consumer.Receive(TimeSpan.FromMilliseconds(100)));
-        //
-        //         testPeer.ExpectEnd();
-        //         testPeer.ExpectClose();
-        //         context.Close();
-        //
-        //         testPeer.WaitForAllMatchersToComplete(2000);
-        //     }
-        // }
-
-        // TODO Connection is started anyway when creating consumer
-        // [Test, Timeout(20_000)]
-        // public void TestNoReceivedNoWaitMessagesWhenConnectionNotStarted()
-        // {
-        //     using (TestAmqpPeer testPeer = new TestAmqpPeer())
-        //     {
-        //         var context = EstablishNMSContext(testPeer);
-        //
-        //         testPeer.ExpectBegin();
-        //
-        //         IQueue destination = context.GetQueue("myQueue");
-        //
-        //         testPeer.ExpectReceiverAttach();
-        //         testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 3);
-        //
-        //         var consumer = context.CreateConsumer(destination);
-        //
-        //         // Wait for a message to arrive then try and receive it, which should not happen
-        //         // since the connection is not started.
-        //         Assert.Null(consumer.ReceiveNoWait());
-        //
-        //         testPeer.ExpectEnd();
-        //         testPeer.ExpectClose();
-        //         context.Close();
-        //
-        //         testPeer.WaitForAllMatchersToComplete(2000);
-        //     }
-        // }
-
         [Test, Timeout(20_000)]
-        public void TestSyncReceiveFailsWhenListenerSet()
+        public async Task TestSyncReceiveFailsWhenListenerSet()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
+                var context = await EstablishNMSContextAsync(testPeer);
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
+                IQueue destination = await context.GetQueueAsync("myQueue");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlow();
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 consumer.Listener += message => { };
 
-                Assert.Catch<NMSException>(() => consumer.Receive(), "Should have thrown an exception.");
-                Assert.Catch<NMSException>(() => consumer.Receive(TimeSpan.FromMilliseconds(1000)), "Should have thrown an exception.");
-                Assert.Catch<NMSException>(() => consumer.ReceiveNoWait(), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => await consumer.ReceiveAsync(), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => await consumer.ReceiveAsync(TimeSpan.FromMilliseconds(1000)), "Should have thrown an exception.");
+                Assert.CatchAsync<NMSException>(async () => consumer.ReceiveNoWait(), "Should have thrown an exception.");
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestCreateProducerInOnMessage()
+        public async Task TestCreateProducerInOnMessage()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                IQueue outbound = context.GetQueue("ForwardDest");
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                IQueue outbound = await context.GetQueueAsync("ForwardDest");
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
@@ -485,7 +428,7 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 consumer.Listener += message =>
                 {
@@ -498,29 +441,29 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsConnectionCloseThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsConnectionCloseThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -547,33 +490,33 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 // testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsConnectionStopThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsConnectionStopThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -600,33 +543,33 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestMessageListenerCallsSessionCloseThrowsIllegalStateException()
+        public async Task TestMessageListenerCallsSessionCloseThrowsIllegalStateException()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -653,11 +596,11 @@ namespace NMS.AMQP.Test.Integration
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.ExpectEnd();
                 // testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
@@ -665,26 +608,26 @@ namespace NMS.AMQP.Test.Integration
 
         // TODO: To be fixed
         [Test, Timeout(20_000), Ignore("Ignore")]
-        public void TestMessageListenerClosesItsConsumer()
+        public async Task TestMessageListenerClosesItsConsumer()
         {
             var latch = new ManualResetEvent(false);
             var exceptionListenerFired = new ManualResetEvent(false);
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 context.ExceptionListener += _ => exceptionListenerFired.Set();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectLinkFlow(drain: true, sendDrainFlowResponse: true, creditMatcher: credit => Assert.AreEqual(99, credit)); // Not sure if expected credit is right
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
@@ -711,7 +654,7 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 Assert.False(exceptionListenerFired.WaitOne(20), "Exception listener shouldn't have fired");
                 testPeer.WaitForAllMatchersToComplete(2000);
@@ -719,7 +662,7 @@ namespace NMS.AMQP.Test.Integration
         }
 
         [Test, Timeout(20_000)]
-        public void TestRecoverOrderingWithAsyncConsumer()
+        public async Task TestRecoverOrderingWithAsyncConsumer()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
             Exception asyncError = null;
@@ -731,13 +674,13 @@ namespace NMS.AMQP.Test.Integration
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer, acknowledgementMode:AcknowledgementMode.ClientAcknowledge);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer, acknowledgementMode:AcknowledgementMode.ClientAcknowledge);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(
@@ -751,7 +694,7 @@ namespace NMS.AMQP.Test.Integration
                     creditMatcher: credit => Assert.Greater(credit, messageCount)
                 );
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
                 
                 bool complete = false;
                 int messageSeen = 0;
@@ -808,31 +751,31 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConsumerCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestConsumerCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -845,37 +788,37 @@ namespace NMS.AMQP.Test.Integration
                 Assert.True(latch.WaitOne(TimeSpan.FromMilliseconds(3000)), "Messages not received within given timeout.");
 
                 testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
-                consumer.Close();
+                await consumer.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestSessionCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestSessionCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -892,31 +835,31 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestConnectionCloseWaitsForAsyncDeliveryToComplete()
+        public async Task TestConnectionCloseWaitsForAsyncDeliveryToComplete()
         {
             ManualResetEvent latch = new ManualResetEvent(false);
 
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
 
-                IQueue destination = context.GetQueue("myQueue");
-                context.Start();
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                await context.StartAsync();
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: CreateMessageWithContent(), count: 1);
 
-                var consumer = context.CreateConsumer(destination);
+                var consumer = await context.CreateConsumerAsync(destination);
 
                 testPeer.ExpectDispositionThatIsAcceptedAndSettled();
 
@@ -930,35 +873,35 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
 
         [Test, Timeout(20_000)]
-        public void TestRecoveredMessageShouldNotBeMutated()
+        public async Task TestRecoveredMessageShouldNotBeMutated()
         {
             using (TestAmqpPeer testPeer = new TestAmqpPeer())
             {
-                var context = EstablishNMSContext(testPeer, acknowledgementMode:AcknowledgementMode.ClientAcknowledge);
-                context.Start();
+                var context = await EstablishNMSContextAsync(testPeer, acknowledgementMode:AcknowledgementMode.ClientAcknowledge);
+                await context.StartAsync();
 
                 testPeer.ExpectBegin();
-                IQueue destination = context.GetQueue("myQueue");
+                IQueue destination = await context.GetQueueAsync("myQueue");
                 string originalPayload = "testMessage";
 
                 testPeer.ExpectReceiverAttach();
                 testPeer.ExpectLinkFlowRespondWithTransfer(message: new Amqp.Message { BodySection = new AmqpValue() { Value = originalPayload } }, count: 1);
 
-                var consumer = context.CreateConsumer(destination);
-                NmsTextMessage message = consumer.Receive() as NmsTextMessage;
+                var consumer = await context.CreateConsumerAsync(destination);
+                NmsTextMessage message = await consumer.ReceiveAsync() as NmsTextMessage;
                 Assert.NotNull(message);
                 message.IsReadOnlyBody = false;
                 message.Text = message.Text + "Received";
-                context.Recover();
+                await context.RecoverAsync();
 
-                ITextMessage recoveredMessage = consumer.Receive() as ITextMessage;
+                ITextMessage recoveredMessage = await consumer.ReceiveAsync() as ITextMessage;
                 Assert.IsNotNull(recoveredMessage);
                 Assert.AreNotEqual(message.Text, recoveredMessage.Text);
                 Assert.AreEqual(originalPayload, recoveredMessage.Text);
@@ -966,10 +909,57 @@ namespace NMS.AMQP.Test.Integration
 
                 testPeer.ExpectEnd();
                 testPeer.ExpectClose();
-                context.Close();
+                await context.CloseAsync();
 
                 testPeer.WaitForAllMatchersToComplete(2000);
             }
         }
+        
+        [TestCaseSource("TestReceiveBodyCaseSource")]
+        [Timeout(20_000)]
+        public async Task TestReceiveBody<T>(T inputValue)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlowRespondWithTransfer(CreateMessageWithValueContent(inputValue));
+                testPeer.ExpectDisposition(true, _ => { } );
+                
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var consumer = await context.CreateConsumerAsync(destination);
+
+                T body = await consumer.ReceiveBodyAsync<T>();
+                Assert.AreEqual(inputValue, body);
+                Assert.AreNotSame(inputValue, body);
+
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(2000);
+            }
+        }
+        
+       
+
+        public static IEnumerable<object> TestReceiveBodyCaseSource()
+        {
+            yield return new Map()
+            {
+                ["Parameter1"] = "test",
+                ["Parameter2"] = 23423
+            };
+            yield return 1233;
+            yield return "test";
+            yield return (uint) 1233;
+            yield return (ulong) 1233;
+            yield return (long) -1233;
+        }
     }
 }
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/NMSContextIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSContextIntegrationTest.cs
new file mode 100644
index 0000000..16940d4
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSContextIntegrationTest.cs
@@ -0,0 +1,279 @@
+/*
+ * 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.Threading.Tasks;
+using Apache.NMS;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    // Adapted from SessionIntegrationTest to use NMSContext
+    [TestFixture]
+    public class NMSContextIntegrationTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestClose()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                INMSContext context = await EstablishNMSContextAsync(testPeer);
+
+                testPeer.ExpectClose();
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateProducer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+
+                testPeer.ExpectSenderAttach();
+
+                var producer = await context.CreateProducerAsync();
+
+                testPeer.ExpectDetach(true, true, true);
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                await producer.CloseAsync();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                var consumer = await context.CreateConsumerAsync(await context.GetQueueAsync("myQueue"));
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerWithEmptySelector()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                await context.CreateConsumerAsync(queue, "");
+                await context.CreateConsumerAsync(queue, "", noLocal: false);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerWithNullSelector()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                await context.CreateConsumerAsync(queue, null);
+                await context.CreateConsumerAsync(queue, null, noLocal: false);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateDurableConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                string topicName = "myTopic";
+                ITopic topic = await context.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectDurableSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+
+                var durableConsumer = await context.CreateDurableConsumerAsync(topic, subscriptionName, null, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateTemporaryQueue()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+
+                testPeer.ExpectBegin();
+
+                string dynamicAddress = "myTempQueueAddress";
+                testPeer.ExpectTempQueueCreationAttach(dynamicAddress);
+
+                ITemporaryQueue temporaryQueue = await context.CreateTemporaryQueueAsync();
+                Assert.NotNull(temporaryQueue, "TemporaryQueue object was null");
+                Assert.NotNull(temporaryQueue.QueueName, "TemporaryQueue queue name was null");
+                Assert.AreEqual(dynamicAddress, temporaryQueue.QueueName, "TemporaryQueue name not as expected");
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateTemporaryTopic()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+
+                testPeer.ExpectBegin();
+
+                string dynamicAddress = "myTempTopicAddress";
+                testPeer.ExpectTempTopicCreationAttach(dynamicAddress);
+
+                ITemporaryTopic temporaryTopic = await context.CreateTemporaryTopicAsync();
+                Assert.NotNull(temporaryTopic, "TemporaryTopic object was null");
+                Assert.NotNull(temporaryTopic.TopicName, "TemporaryTopic name was null");
+                Assert.AreEqual(dynamicAddress, temporaryTopic.TopicName, "TemporaryTopic name not as expected");
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateSharedConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                string topicName = "myTopic";
+                ITopic topic = await context.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectSharedSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+
+                var durableConsumer = await context.CreateSharedConsumerAsync(topic, subscriptionName, null); //, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(20000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateSharedDurableConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                string topicName = "myTopic";
+                ITopic topic = await context.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectSharedDurableSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+
+                var durableConsumer = await context.CreateSharedDurableConsumerAsync(topic, subscriptionName, null); //, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/NMSProducerIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSProducerIntegrationTest.cs
new file mode 100644
index 0000000..4d5ca30
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/NMSProducerIntegrationTest.cs
@@ -0,0 +1,723 @@
+/*
+ * 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 System.Threading.Tasks;
+using Amqp.Framing;
+using Amqp.Types;
+using Apache.NMS;
+using Apache.NMS.AMQP.Util;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    // Adapted from ProducerIntegrationTest to use NMSContext
+    [TestFixture]
+    public class NMSProducerIntegrationTestAsync : IntegrationTestFixture
+    {
+        private const long TICKS_PER_MILLISECOND = 10000;
+
+        [Test, Timeout(20_000)]
+        public async Task TestCloseSender()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await base.EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                await producer.CloseAsync();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSentTextMessageCanBeModified()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await base.EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                // Create and transfer a new message
+                String text = "myMessage";
+                testPeer.ExpectTransfer(x => Assert.AreEqual(text, (x.BodySection as AmqpValue).Value));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+                await producer.SendAsync(queue, message);
+
+                Assert.AreEqual(text, message.Text);
+                message.Text = text + text;
+                Assert.AreEqual(text + text, message.Text);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestDefaultDeliveryModeProducesDurableMessages()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await base.EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                // Create and transfer a new message
+                testPeer.ExpectTransfer(message => Assert.IsTrue(message.Header.Durable));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage textMessage = await context.CreateTextMessageAsync();
+
+                await producer.SendAsync(queue, textMessage);
+                Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestProducerOverridesMessageDeliveryMode()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await base.EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                // Create and transfer a new message, explicitly setting the deliveryMode on the
+                // message (which applications shouldn't) to NON_PERSISTENT and sending it to check
+                // that the producer ignores this value and sends the message as PERSISTENT(/durable)
+                testPeer.ExpectTransfer(message => Assert.IsTrue(message.Header.Durable));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage textMessage = await context.CreateTextMessageAsync();
+                textMessage.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;
+                Assert.AreEqual(MsgDeliveryMode.NonPersistent, textMessage.NMSDeliveryMode);
+
+                await producer.SendAsync(queue, textMessage);
+
+                Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
+
+                await context.CloseAsync();
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerSetDurableFalse()
+        {
+            await DoSendingMessageNonPersistentTestImpl(true);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerOmitsHeader()
+        {
+            await DoSendingMessageNonPersistentTestImpl(false);
+        }
+
+        private async Task DoSendingMessageNonPersistentTestImpl(bool setPriority)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                //Add capability to indicate support for ANONYMOUS-RELAY
+                Symbol[] serverCapabilities = {SymbolUtil.OPEN_CAPABILITY_ANONYMOUS_RELAY};
+                var context = await EstablishNMSContextAsync(testPeer, serverCapabilities: serverCapabilities);
+                testPeer.ExpectBegin();
+
+                string queueName = "myQueue";
+                Action<object> targetMatcher = t =>
+                {
+                    var target = t as Target;
+                    Assert.IsNotNull(target);
+                };
+
+
+                testPeer.ExpectSenderAttach(targetMatcher: targetMatcher, sourceMatcher: Assert.NotNull, senderSettled: false);
+
+                IQueue queue = await context.GetQueueAsync(queueName);
+                INMSProducer producer = await context.CreateProducerAsync();
+
+                byte priority = 5;
+                String text = "myMessage";
+                testPeer.ExpectTransfer(messageMatcher: message =>
+                    {
+                        if (setPriority)
+                        {
+                            Assert.IsFalse(message.Header.Durable);
+                            Assert.AreEqual(priority, message.Header.Priority);
+                        }
+
+                        Assert.AreEqual(text, (message.BodySection as AmqpValue).Value);
+                    }, stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true);
+
+                ITextMessage textMessage = await context.CreateTextMessageAsync(text);
+
+                producer.DeliveryMode = MsgDeliveryMode.NonPersistent;
+                if (setPriority)
+                    producer.Priority = (MsgPriority) priority;
+
+                await producer.SendAsync(queue, textMessage);
+
+                Assert.AreEqual(MsgDeliveryMode.NonPersistent, textMessage.NMSDeliveryMode, "Should have NonPersistent delivery mode set");
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSDestination()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                string text = "myMessage";
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(text, (m.BodySection as AmqpValue).Value));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                Assert.IsNull(message.NMSDestination, "Should not yet have a NMSDestination");
+
+                await producer.SendAsync(destination, message);
+
+                Assert.AreEqual(destination, message.NMSDestination, "Should have had NMSDestination set");
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSTimestamp()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                // Create matcher to expect the absolute-expiry-time field of the properties section to
+                // be set to a value greater than 'now'+ttl, within a delta.
+
+                DateTime creationLower = DateTime.UtcNow;
+                DateTime creationUpper = creationLower + TimeSpan.FromMilliseconds(3000);
+
+                var text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.That(m.Properties.CreationTime.Ticks, Is.GreaterThanOrEqualTo(creationLower.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.That(m.Properties.CreationTime.Ticks, Is.LessThanOrEqualTo(creationUpper.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+                await producer.SendAsync(destination, message);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSExpirationRelatedAbsoluteExpiryAndTtlFields()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                uint ttl = 100_000;
+                DateTime currentTime = DateTime.UtcNow;
+                DateTime expirationLower = currentTime + TimeSpan.FromMilliseconds(ttl);
+                DateTime expirationUpper = currentTime + TimeSpan.FromMilliseconds(ttl) + TimeSpan.FromMilliseconds(5000);
+
+                // Create matcher to expect the absolute-expiry-time field of the properties section to
+                // be set to a value greater than 'now'+ttl, within a delta.
+                string text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.AreEqual(ttl, m.Header.Ttl);
+                    Assert.That(m.Properties.AbsoluteExpiryTime.Ticks, Is.GreaterThanOrEqualTo(expirationLower.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.That(m.Properties.AbsoluteExpiryTime.Ticks, Is.LessThanOrEqualTo(expirationUpper.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+                producer.TimeToLive = TimeSpan.FromMilliseconds(ttl);
+                producer.Priority = NMSConstants.defaultPriority;
+                producer.DeliveryMode = NMSConstants.defaultDeliveryMode;
+                await producer.SendAsync(destination, message);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestMessagesAreProducedWithProperDefaultPriorityWhenNoPrioritySpecified()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                byte priority = 4;
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(priority, m.Header.Priority));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage message = await context.CreateTextMessageAsync();
+                Assert.AreEqual(MsgPriority.BelowNormal, message.NMSPriority);
+
+                await producer.SendAsync(destination, message);
+
+                Assert.AreEqual((MsgPriority) priority, message.NMSPriority);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestNonDefaultPriorityProducesMessagesWithPriorityFieldAndSetsNMSPriority()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                byte priority = 9;
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(priority, m.Header.Priority));
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage message = await context.CreateTextMessageAsync();
+                Assert.AreEqual(MsgPriority.BelowNormal, message.NMSPriority);
+
+                producer.DeliveryMode = MsgDeliveryMode.Persistent;
+                producer.Priority = (MsgPriority) priority;
+                producer.TimeToLive = NMSConstants.defaultTimeToLive;
+                await producer.SendAsync(destination, message);
+
+                Assert.AreEqual((MsgPriority) priority, message.NMSPriority);
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSMessageId()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                string text = "myMessage";
+                string actualMessageId = null;
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.IsNotEmpty(m.Properties.MessageId);
+                    actualMessageId = m.Properties.MessageId;
+                });
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+                Assert.IsNull(message.NMSMessageId, "NMSMessageId should not yet be set");
+
+                await producer.SendAsync(destination, message);
+
+                Assert.IsNotNull(message.NMSMessageId);
+                Assert.IsNotEmpty(message.NMSMessageId, "NMSMessageId should be set");
+                Assert.IsTrue(message.NMSMessageId.StartsWith("ID:"), "MMS 'ID:' prefix not found");
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+                // Get the value that was actually transmitted/received, verify it is a string, compare to what we have locally
+                Assert.AreEqual(message.NMSMessageId, actualMessageId, "Expected NMSMessageId value to be present in AMQP message");
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageWithDisableMessageIdHint()
+        {
+            await DoSendingMessageWithDisableMessageIdHintTestImpl(false);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageWithDisableMessageIdHintAndExistingMessageId()
+        {
+            await DoSendingMessageWithDisableMessageIdHintTestImpl(true);
+        }
+
+        private async Task DoSendingMessageWithDisableMessageIdHintTestImpl(bool existingId)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                string text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.IsNull(m.Properties.MessageId); // Check there is no message-id value;
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                ITextMessage message = await context.CreateTextMessageAsync(text);
+
+                Assert.IsNull(message.NMSMessageId, "NMSMessageId should not yet be set");
+
+                if (existingId)
+                {
+                    string existingMessageId = "ID:this-should-be-overwritten-in-send";
+                    message.NMSMessageId = existingMessageId;
+                    Assert.AreEqual(existingMessageId, message.NMSMessageId, "NMSMessageId should now be se");
+                }
+
+                producer.DisableMessageID = true;
+
+                await producer.SendAsync(destination, message);
+
+                Assert.IsNull(message.NMSMessageId, "NMSMessageID should be null");
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(2000);
+            }
+        }
+
+        // TODO No connection listener in nms context
+        // [Test, Timeout(20_000)]
+        // public async Task TestRemotelyCloseProducer()
+        // {
+        //     string breadCrumb = "ErrorMessageBreadCrumb";
+        //
+        //     ManualResetEvent producerClosed = new ManualResetEvent(false);
+        //     Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
+        //     mockConnectionListener
+        //         .Setup(listener => listener.OnProducerClosed(It.IsAny<NmsMessageProducer>(), It.IsAny<Exception>()))
+        //         .Callback(() => { producerClosed.Set(); });
+        //
+        //     using (TestAmqpPeer testPeer = new TestAmqpPeer())
+        //     {
+        //         NmsContext context = (NmsContext) EstablishNMSContext(testPeer);
+        //         context.AddConnectionListener(mockConnectionListener.Object);
+        //
+        //         testPeer.ExpectBegin();
+        //         ISession session = context.CreateSession(AcknowledgementMode.AutoAcknowledge);
+        //
+        //         // Create a producer, then remotely end it afterwards.
+        //         testPeer.ExpectSenderAttach();
+        //         testPeer.RemotelyDetachLastOpenedLinkOnLastOpenedSession(expectDetachResponse: true, closed: true, errorType: AmqpError.RESOURCE_DELETED, breadCrumb, delayBeforeSend: 10);
+        //
+        //         IQueue destination = session.GetQueue("myQueue");
+        //         IMessageProducer producer = session.CreateProducer(destination);
+        //
+        //         // Verify the producer gets marked closed
+        //         testPeer.WaitForAllMatchersToComplete(1000);
+        //
+        //         Assert.True(producerClosed.WaitOne(TimeSpan.FromMilliseconds(1000)), "Producer closed callback didn't trigger");
+        //         Assert.That(() => producer.DisableMessageID, Throws.Exception.InstanceOf<IllegalStateException>(), "Producer never closed");
+        //
+        //         // Try closing it explicitly, should effectively no-op in client.
+        //         // The test peer will throw during close if it sends anything.
+        //         producer.Close();
+        //     }
+        // }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWhenLinkCreditIsZeroAndTimeout()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer, optionsString: "nms.sendTimeout=500");
+                testPeer.ExpectBegin();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+
+                ITextMessage message = await context.CreateTextMessageAsync("text");
+
+                // Expect the producer to attach. Don't send any credit so that the client will
+                // block on a send and we can test our timeouts.
+                testPeer.ExpectSenderAttachWithoutGrantingCredit();
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                var producer = await context.CreateProducerAsync();
+
+                Assert.CatchAsync<Exception>(async () => await producer.SendAsync(queue, message), "Send should time out.");
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendTimesOutWhenNoDispositionArrives()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer, optionsString: "nms.sendTimeout=500");
+                testPeer.ExpectBegin();
+
+                IQueue queue = await context.GetQueueAsync("myQueue");
+
+                ITextMessage message = await context.CreateTextMessageAsync("text");
+
+                // Expect the producer to attach and grant it some credit, it should send
+                // a transfer which we will not send any response for which should cause the
+                // send operation to time out.
+                testPeer.ExpectSenderAttach();
+                testPeer.ExpectTransferButDoNotRespond(messageMatcher: Assert.NotNull);
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                var producer = await context.CreateProducerAsync();
+
+                Assert.CatchAsync<Exception>(async () => await producer.SendAsync(queue, message), "Send should time out.");
+
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWorksWhenConnectionNotStarted()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                testPeer.ExpectTransfer(Assert.IsNotNull);
+
+                await producer.SendAsync(destination, await context.CreateMessageAsync());
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                await producer.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWorksAfterConnectionStopped()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+
+                testPeer.ExpectTransfer(Assert.IsNotNull);
+
+                await context.StopAsync();
+
+                await producer.SendAsync(destination, await context.CreateMessageAsync());
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                await producer.CloseAsync();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessagePersistentSetsBatchableFalse()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+                testPeer.ExpectTransfer(messageMatcher: Assert.IsNotNull,
+                    stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    batchable: false);
+
+                IMessage message = await context.CreateMessageAsync();
+                producer.DeliveryMode = MsgDeliveryMode.Persistent;
+                producer.Priority = MsgPriority.Normal;
+                producer.TimeToLive = NMSConstants.defaultTimeToLive;
+                await producer.SendAsync(destination, message);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSetsBatchableFalse()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                var context = await EstablishNMSContextAsync(testPeer);
+                await context.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                IQueue destination = await context.GetQueueAsync("myQueue");
+                var producer = await context.CreateProducerAsync();
+                testPeer.ExpectTransfer(messageMatcher: Assert.IsNotNull,
+                    stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    batchable: false);
+
+                IMessage message = await context.CreateMessageAsync();
+                producer.DeliveryMode = MsgDeliveryMode.NonPersistent;
+                producer.Priority = MsgPriority.Normal;
+                producer.TimeToLive = NMSConstants.defaultTimeToLive;
+                await producer.SendAsync(destination, message);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+                await context.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationAsyncTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationAsyncTest.cs
new file mode 100644
index 0000000..641b36b
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationAsyncTest.cs
@@ -0,0 +1,135 @@
+/*
+ * 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 System.Threading.Tasks;
+using Amqp.Framing;
+using Apache.NMS;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class ProducerIntegrationAsyncTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestSentAsyncIsAsynchronous()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message
+                String text = "myMessage";
+                testPeer.ExpectTransfer(messageMatcher: m => Assert.AreEqual(text, (m.BodySection as AmqpValue).Value),
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    stateMatcher: Assert.IsNull,
+                    dispositionDelay: 10); // 10ms should be enough
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                var sendTask = producer.SendAsync(message);
+                // Instantly check if its not completed yet, we want async, so it should not be completed right after 
+                Assert.AreEqual(false, sendTask.IsCompleted);
+                
+                // And now wait for task to complete
+                sendTask.Wait(20_000);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestSentAsync()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message
+                String text = "myMessage";
+                testPeer.ExpectTransfer(messageMatcher: m => Assert.AreEqual(text, (m.BodySection as AmqpValue).Value),
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    stateMatcher: Assert.IsNull,
+                    dispositionDelay: 10); // 10ms should be enough
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                await producer.SendAsync(message);
+              
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+       
+
+        [Test, Timeout(20_000)]
+        public async Task TestProducerWorkWithAsyncAwait()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message, explicitly setting the deliveryMode on the
+                // message (which applications shouldn't) to NON_PERSISTENT and sending it to check
+                // that the producer ignores this value and sends the message as PERSISTENT(/durable)
+                testPeer.ExpectTransfer(message => Assert.IsTrue(message.Header.Durable));
+                testPeer.ExpectClose();
+
+                ITextMessage textMessage = await session.CreateTextMessageAsync();
+                textMessage.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;
+                Assert.AreEqual(MsgDeliveryMode.NonPersistent, textMessage.NMSDeliveryMode);
+
+                await producer.SendAsync(textMessage);
+
+                Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
+
+                await connection.CloseAsync();
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationTest.cs
new file mode 100644
index 0000000..f1328a0
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/ProducerIntegrationTest.cs
@@ -0,0 +1,782 @@
+/*
+ * 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 System.Threading;
+using System.Threading.Tasks;
+using Amqp.Framing;
+using Amqp.Types;
+using Apache.NMS;
+using Apache.NMS.AMQP;
+using Apache.NMS.AMQP.Util;
+using Moq;
+using NMS.AMQP.Test.TestAmqp;
+using NMS.AMQP.Test.TestAmqp.BasicTypes;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class ProducerIntegrationTestAsync : IntegrationTestFixture
+    {
+        private const long TICKS_PER_MILLISECOND = 10000;
+
+        [Test, Timeout(20_000)]
+        public async Task TestCloseSender()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync();
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                testPeer.ExpectClose();
+
+                await producer.CloseAsync();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSentTextMessageCanBeModified()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message
+                String text = "myMessage";
+                testPeer.ExpectTransfer(x => Assert.AreEqual(text, (x.BodySection as AmqpValue).Value));
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                await producer.SendAsync(message);
+
+                Assert.AreEqual(text, message.Text);
+                message.Text = text + text;
+                Assert.AreEqual(text + text, message.Text);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestDefaultDeliveryModeProducesDurableMessages()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message
+                testPeer.ExpectTransfer(message => Assert.IsTrue(message.Header.Durable));
+                testPeer.ExpectClose();
+
+                ITextMessage textMessage = await session.CreateTextMessageAsync();
+
+                await producer.SendAsync(textMessage);
+                Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestProducerOverridesMessageDeliveryMode()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await base.EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                // Create and transfer a new message, explicitly setting the deliveryMode on the
+                // message (which applications shouldn't) to NON_PERSISTENT and sending it to check
+                // that the producer ignores this value and sends the message as PERSISTENT(/durable)
+                testPeer.ExpectTransfer(message => Assert.IsTrue(message.Header.Durable));
+                testPeer.ExpectClose();
+
+                ITextMessage textMessage = await session.CreateTextMessageAsync();
+                textMessage.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;
+                Assert.AreEqual(MsgDeliveryMode.NonPersistent, textMessage.NMSDeliveryMode);
+
+                await producer.SendAsync(textMessage);
+
+                Assert.AreEqual(MsgDeliveryMode.Persistent, textMessage.NMSDeliveryMode);
+
+                await connection.CloseAsync();
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerSetDurableFalse()
+        {
+            await DoSendingMessageNonPersistentTestImpl(false, true, true);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerSetDurableFalseAnonymousProducer()
+        {
+            await DoSendingMessageNonPersistentTestImpl(true, true, true);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSendSetDurableFalse()
+        {
+            await DoSendingMessageNonPersistentTestImpl(false, true, false);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSendSetDurableFalseAnonymousProducer()
+        {
+            await DoSendingMessageNonPersistentTestImpl(true, true, false);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerOmitsHeader()
+        {
+            await DoSendingMessageNonPersistentTestImpl(false, false, true);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentProducerOmitsHeaderAnonymousProducer()
+        {
+            await DoSendingMessageNonPersistentTestImpl(true, false, true);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSendOmitsHeader()
+        {
+            await DoSendingMessageNonPersistentTestImpl(false, false, false);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSendOmitsHeaderAnonymousProducer()
+        {
+            await DoSendingMessageNonPersistentTestImpl(true, false, false);
+        }
+
+        private async Task DoSendingMessageNonPersistentTestImpl(bool anonymousProducer, bool setPriority, bool setOnProducer)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                //Add capability to indicate support for ANONYMOUS-RELAY
+                Symbol[] serverCapabilities = { SymbolUtil.OPEN_CAPABILITY_ANONYMOUS_RELAY };
+                IConnection connection = await EstablishConnectionAsync(testPeer, serverCapabilities: serverCapabilities);
+                testPeer.ExpectBegin();
+
+                string queueName = "myQueue";
+                Action<object> targetMatcher = t =>
+                {
+                    var target = t as Target;
+                    Assert.IsNotNull(target);
+                    if (anonymousProducer)
+                        Assert.IsNull(target.Address);
+                    else
+                        Assert.AreEqual(queueName, target.Address);
+                };
+                
+
+                testPeer.ExpectSenderAttach(targetMatcher: targetMatcher, sourceMatcher: Assert.NotNull, senderSettled: false);
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync(queueName);
+                IMessageProducer producer = null;
+                if (anonymousProducer)
+                    producer = await session.CreateProducerAsync();
+                else
+                    producer = await session.CreateProducerAsync(queue);
+
+                byte priority = 5;
+                String text = "myMessage";
+                testPeer.ExpectTransfer(messageMatcher: message =>
+                    {
+                        if (setPriority)
+                        {
+                            Assert.IsFalse(message.Header.Durable);
+                            Assert.AreEqual(5, message.Header.Priority);
+                        }
+
+                        Assert.AreEqual(text, (message.BodySection as AmqpValue).Value);
+                    }, stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true);
+
+                ITextMessage textMessage = await session.CreateTextMessageAsync(text);
+
+                if (setOnProducer)
+                {
+                    producer.DeliveryMode = MsgDeliveryMode.NonPersistent;
+                    if (setPriority)
+                        producer.Priority = (MsgPriority) 5;
+
+                    if (anonymousProducer)
+                        await producer.SendAsync(queue, textMessage);
+                    else
+                        await producer.SendAsync(textMessage);
+                }
+                else
+                {
+                    if (anonymousProducer)
+                    {
+                        await producer.SendAsync(destination: queue,
+                            message: textMessage,
+                            deliveryMode: MsgDeliveryMode.NonPersistent,
+                            priority: setPriority ? (MsgPriority) priority : NMSConstants.defaultPriority,
+                            timeToLive: NMSConstants.defaultTimeToLive);
+                    }
+                    else
+                    {
+                        await producer.SendAsync(message: textMessage,
+                            deliveryMode: MsgDeliveryMode.NonPersistent,
+                            priority: setPriority ? (MsgPriority) priority : NMSConstants.defaultPriority,
+                            timeToLive: NMSConstants.defaultTimeToLive);
+                    }
+                }
+
+                Assert.AreEqual(MsgDeliveryMode.NonPersistent, textMessage.NMSDeliveryMode, "Should have NonPersistent delivery mode set");
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSDestination()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                string text = "myMessage";
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(text, (m.BodySection as AmqpValue).Value));
+                testPeer.ExpectClose();
+
+                Assert.IsNull(message.NMSDestination, "Should not yet have a NMSDestination");
+
+                await producer.SendAsync(message);
+
+                Assert.AreEqual(destination, message.NMSDestination, "Should have had NMSDestination set");
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSTimestamp()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                // Create matcher to expect the absolute-expiry-time field of the properties section to
+                // be set to a value greater than 'now'+ttl, within a delta.
+
+                DateTime creationLower = DateTime.UtcNow;
+                DateTime creationUpper = creationLower + TimeSpan.FromMilliseconds(3000);
+
+                var text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.That(m.Properties.CreationTime.Ticks, Is.GreaterThanOrEqualTo(creationLower.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.That(m.Properties.CreationTime.Ticks, Is.LessThanOrEqualTo(creationUpper.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                await producer.SendAsync(message);
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSExpirationRelatedAbsoluteExpiryAndTtlFields()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                uint ttl = 100_000;
+                DateTime currentTime = DateTime.UtcNow;
+                DateTime expirationLower = currentTime + TimeSpan.FromMilliseconds(ttl);
+                DateTime expirationUpper = currentTime + TimeSpan.FromMilliseconds(ttl) + TimeSpan.FromMilliseconds(5000);
+
+                // Create matcher to expect the absolute-expiry-time field of the properties section to
+                // be set to a value greater than 'now'+ttl, within a delta.
+                string text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.AreEqual(ttl, m.Header.Ttl);
+                    Assert.That(m.Properties.AbsoluteExpiryTime.Ticks, Is.GreaterThanOrEqualTo(expirationLower.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.That(m.Properties.AbsoluteExpiryTime.Ticks, Is.LessThanOrEqualTo(expirationUpper.Ticks).Within(TICKS_PER_MILLISECOND));
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                await producer.SendAsync(message, NMSConstants.defaultDeliveryMode, NMSConstants.defaultPriority, TimeSpan.FromMilliseconds(ttl));
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestMessagesAreProducedWithProperDefaultPriorityWhenNoPrioritySpecified()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                byte priority = 4;
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(priority, m.Header.Priority));
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync();
+                Assert.AreEqual(MsgPriority.BelowNormal, message.NMSPriority);
+
+                await producer.SendAsync(message);
+
+                Assert.AreEqual((MsgPriority) priority, message.NMSPriority);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestNonDefaultPriorityProducesMessagesWithPriorityFieldAndSetsNMSPriority()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                byte priority = 9;
+
+                testPeer.ExpectTransfer(m => Assert.AreEqual(priority, m.Header.Priority));
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync();
+                Assert.AreEqual(MsgPriority.BelowNormal, message.NMSPriority);
+
+                await producer.SendAsync(message, MsgDeliveryMode.Persistent, (MsgPriority) priority, NMSConstants.defaultTimeToLive);
+
+                Assert.AreEqual((MsgPriority) priority, message.NMSPriority);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageSetsNMSMessageId()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                string text = "myMessage";
+                string actualMessageId = null;
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.IsNotEmpty(m.Properties.MessageId);
+                    actualMessageId = m.Properties.MessageId;
+                });
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+                Assert.IsNull(message.NMSMessageId, "NMSMessageId should not yet be set");
+
+                await producer.SendAsync(message);
+
+                Assert.IsNotNull(message.NMSMessageId);
+                Assert.IsNotEmpty(message.NMSMessageId, "NMSMessageId should be set");
+                Assert.IsTrue(message.NMSMessageId.StartsWith("ID:"), "MMS 'ID:' prefix not found");
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+                // Get the value that was actually transmitted/received, verify it is a string, compare to what we have locally
+                Assert.AreEqual(message.NMSMessageId, actualMessageId, "Expected NMSMessageId value to be present in AMQP message");
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageWithDisableMessageIdHint()
+        {
+            await DoSendingMessageWithDisableMessageIdHintTestImpl(false);
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageWithDisableMessageIdHintAndExistingMessageId()
+        {
+            await DoSendingMessageWithDisableMessageIdHintTestImpl(true);
+        }
+
+        private async Task DoSendingMessageWithDisableMessageIdHintTestImpl(bool existingId)
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                string text = "myMessage";
+                testPeer.ExpectTransfer(m =>
+                {
+                    Assert.IsTrue(m.Header.Durable);
+                    Assert.IsNull(m.Properties.MessageId); // Check there is no message-id value;
+                    Assert.AreEqual(text, (m.BodySection as AmqpValue).Value);
+                });
+                testPeer.ExpectClose();
+
+                ITextMessage message = await session.CreateTextMessageAsync(text);
+
+                Assert.IsNull(message.NMSMessageId, "NMSMessageId should not yet be set");
+
+                if (existingId)
+                {
+                    string existingMessageId = "ID:this-should-be-overwritten-in-send";
+                    message.NMSMessageId = existingMessageId;
+                    Assert.AreEqual(existingMessageId, message.NMSMessageId, "NMSMessageId should now be se");
+                }
+
+                producer.DisableMessageID = true;
+
+                await producer.SendAsync(message);
+
+                Assert.IsNull(message.NMSMessageId, "NMSMessageID should be null");
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(2000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestRemotelyCloseProducer()
+        {
+            string breadCrumb = "ErrorMessageBreadCrumb";
+
+            ManualResetEvent producerClosed = new ManualResetEvent(false);
+            Mock<INmsConnectionListener> mockConnectionListener = new Mock<INmsConnectionListener>();
+            mockConnectionListener
+                .Setup(listener => listener.OnProducerClosed(It.IsAny<NmsMessageProducer>(), It.IsAny<Exception>()))
+                .Callback(() => { producerClosed.Set(); });
+
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                NmsConnection connection = (NmsConnection) await EstablishConnectionAsync(testPeer);
+                connection.AddConnectionListener(mockConnectionListener.Object);
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                // Create a producer, then remotely end it afterwards.
+                testPeer.ExpectSenderAttach();
+                testPeer.RemotelyDetachLastOpenedLinkOnLastOpenedSession(expectDetachResponse: true, closed: true, errorType: AmqpError.RESOURCE_DELETED, breadCrumb, delayBeforeSend: 10);
+
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                // Verify the producer gets marked closed
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                Assert.True(producerClosed.WaitOne(TimeSpan.FromMilliseconds(1000)), "Producer closed callback didn't trigger");
+                Assert.That(() => producer.DisableMessageID, Throws.Exception.InstanceOf<IllegalStateException>(), "Producer never closed");
+
+                // Try closing it explicitly, should effectively no-op in client.
+                // The test peer will throw during close if it sends anything.
+                await producer.CloseAsync();
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWhenLinkCreditIsZeroAndTimeout()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer, optionsString: "nms.sendTimeout=500");
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                ITextMessage message = await session.CreateTextMessageAsync("text");
+
+                // Expect the producer to attach. Don't send any credit so that the client will
+                // block on a send and we can test our timeouts.
+                testPeer.ExpectSenderAttachWithoutGrantingCredit();
+                testPeer.ExpectClose();
+
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                Assert.CatchAsync<Exception>(async () => await producer.SendAsync(message), "Send should time out.");
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendTimesOutWhenNoDispositionArrives()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer, optionsString: "nms.sendTimeout=500");
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue queue = await session.GetQueueAsync("myQueue");
+
+                ITextMessage message = await session.CreateTextMessageAsync("text");
+
+                // Expect the producer to attach and grant it some credit, it should send
+                // a transfer which we will not send any response for which should cause the
+                // send operation to time out.
+                testPeer.ExpectSenderAttach();
+                testPeer.ExpectTransferButDoNotRespond(messageMatcher: Assert.NotNull);
+                testPeer.ExpectClose();
+
+                IMessageProducer producer = await session.CreateProducerAsync(queue);
+
+                Assert.CatchAsync<Exception>(async () => await producer.SendAsync(message), "Send should time out.");
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWorksWhenConnectionNotStarted()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                testPeer.ExpectTransfer(Assert.IsNotNull);
+
+                await producer.SendAsync(await session.CreateMessageAsync());
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                await producer.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendWorksAfterConnectionStopped()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+
+                testPeer.ExpectTransfer(Assert.IsNotNull);
+
+                await connection.StopAsync();
+
+                await producer.SendAsync(await session.CreateMessageAsync());
+
+                testPeer.ExpectDetach(expectClosed: true, sendResponse: true, replyClosed: true);
+                testPeer.ExpectClose();
+
+                await producer.CloseAsync();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+  
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessagePersistentSetsBatchableFalse()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+                testPeer.ExpectTransfer(messageMatcher: Assert.IsNotNull,
+                    stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    batchable: false);
+
+                IMessage message = await session.CreateMessageAsync();
+                await producer.SendAsync(message: message, deliveryMode: MsgDeliveryMode.Persistent, MsgPriority.Normal, NMSConstants.defaultTimeToLive);
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestSendingMessageNonPersistentSetsBatchableFalse()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                testPeer.ExpectSenderAttach();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                IQueue destination = await session.GetQueueAsync("myQueue");
+                IMessageProducer producer = await session.CreateProducerAsync(destination);
+                testPeer.ExpectTransfer(messageMatcher: Assert.IsNotNull,
+                    stateMatcher: Assert.IsNull,
+                    settled: false,
+                    sendResponseDisposition: true,
+                    responseState: new Accepted(),
+                    responseSettled: true,
+                    batchable: false);
+
+                IMessage message = await session.CreateMessageAsync();
+                await producer.SendAsync(message: message, deliveryMode: MsgDeliveryMode.NonPersistent, MsgPriority.Normal, NMSConstants.defaultTimeToLive);
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/SessionIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/SessionIntegrationTest.cs
new file mode 100644
index 0000000..ca34e19
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/SessionIntegrationTest.cs
@@ -0,0 +1,289 @@
+/*
+ * 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.Threading.Tasks;
+using Apache.NMS;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class SessionIntegrationTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestCloseSession()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                Assert.NotNull(session, "Session should not be null");
+                testPeer.ExpectEnd();
+                testPeer.ExpectClose();
+
+                await session.CloseAsync();
+
+                // Should send nothing and throw no error.
+                await session.CloseAsync();
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateProducer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                testPeer.ExpectSenderAttach();
+                testPeer.ExpectClose();
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                await session.CreateProducerAsync(queue);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectClose();
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                await session.CreateConsumerAsync(queue);
+
+                await connection.CloseAsync();
+
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerWithEmptySelector()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectClose();
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                await session.CreateConsumerAsync(queue, "");
+                await session.CreateConsumerAsync(queue, "", noLocal: false);
+                
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateConsumerWithNullSelector()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectReceiverAttach();
+                testPeer.ExpectLinkFlow();
+                testPeer.ExpectClose();
+
+                IQueue queue = await session.GetQueueAsync("myQueue");
+                await session.CreateConsumerAsync(queue, null);
+                await session.CreateConsumerAsync(queue, null, noLocal: false);
+                
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+
+        [Test, Timeout(20_000)]
+        public async Task TestCreateDurableConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                
+                string topicName = "myTopic";
+                ITopic topic = await session.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectDurableSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+                
+                IMessageConsumer durableConsumer = await session.CreateDurableConsumerAsync(topic, subscriptionName, null, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestCreateTemporaryQueue()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                
+                string dynamicAddress = "myTempQueueAddress";
+                testPeer.ExpectTempQueueCreationAttach(dynamicAddress);
+                
+                ITemporaryQueue temporaryQueue = await session.CreateTemporaryQueueAsync();
+                Assert.NotNull(temporaryQueue, "TemporaryQueue object was null");
+                Assert.NotNull(temporaryQueue.QueueName, "TemporaryQueue queue name was null");
+                Assert.AreEqual(dynamicAddress, temporaryQueue.QueueName, "TemporaryQueue name not as expected");
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestCreateTemporaryTopic()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                
+                string dynamicAddress = "myTempTopicAddress";
+                testPeer.ExpectTempTopicCreationAttach(dynamicAddress);
+                
+                ITemporaryTopic temporaryTopic = await session.CreateTemporaryTopicAsync();
+                Assert.NotNull(temporaryTopic, "TemporaryTopic object was null");
+                Assert.NotNull(temporaryTopic.TopicName, "TemporaryTopic name was null");
+                Assert.AreEqual(dynamicAddress, temporaryTopic.TopicName, "TemporaryTopic name not as expected");
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+       
+        [Test, Timeout(20_000)]
+        public async Task TestCreateSharedConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                
+                string topicName = "myTopic";
+                ITopic topic = await session.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectSharedSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+                
+                IMessageConsumer durableConsumer = await session.CreateSharedConsumerAsync(topic, subscriptionName, null);//, false);
+                // IMessageConsumer durableConsumer = session.CreateDurableConsumer(topic, subscriptionName, null, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(20000);
+            }
+        }
+        
+        [Test, Timeout(20_000)]
+        public async Task TestCreateSharedDurableConsumer()
+        {
+            using (TestAmqpPeer testPeer = new TestAmqpPeer())
+            {
+                IConnection connection = await EstablishConnectionAsync(testPeer);
+                await connection.StartAsync();
+
+                testPeer.ExpectBegin();
+                ISession session = await connection.CreateSessionAsync(AcknowledgementMode.AutoAcknowledge);
+                
+                string topicName = "myTopic";
+                ITopic topic = await session.GetTopicAsync(topicName);
+                string subscriptionName = "mySubscription";
+
+                testPeer.ExpectSharedDurableSubscriberAttach(topicName, subscriptionName);
+                testPeer.ExpectLinkFlow();
+                
+                IMessageConsumer durableConsumer = await session.CreateSharedDurableConsumerAsync(topic, subscriptionName, null); //, false);
+                Assert.NotNull(durableConsumer, "MessageConsumer object was null");
+                
+                testPeer.ExpectClose();
+                await connection.CloseAsync();
+                
+                testPeer.WaitForAllMatchersToComplete(1000);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Apache-NMS-AMQP-Test/Integration/Async/SubscriptionsIntegrationTest.cs b/test/Apache-NMS-AMQP-Test/Integration/Async/SubscriptionsIntegrationTest.cs
new file mode 100644
index 0000000..52c5920
--- /dev/null
+++ b/test/Apache-NMS-AMQP-Test/Integration/Async/SubscriptionsIntegrationTest.cs
@@ -0,0 +1,74 @@
+/*
+ * 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 System.Threading.Tasks;
+using Apache.NMS;
+using NMS.AMQP.Test.TestAmqp;
+using NUnit.Framework;
+
+namespace NMS.AMQP.Test.Integration.Async
+{
+    [TestFixture]
+    public class SubscriptionsIntegrationTestAsync : IntegrationTestFixture
+    {
+        [Test, Timeout(20_000)]
+        public async Task TestUnsubscribeExclusiveDurableSubWhileActiveThenInactive()
+        {
... 2500 lines suppressed ...