A MessageListenerContainer that uses local (non-DTC) based transactions. Exceptions are handled by instances of IMessageTransactionExceptionHandler.

This container distinguishes between two types of IPlatformTransactionManager implementations.

If you specify a MessageQueueTransactionManager then a MSMQ MessageQueueTransaction will be started before receiving the message and used as part of the container's recieve operation. The MessageQueueTransactionManager binds the MessageQueueTransaction to thread local storage and as such will implicitly be used by MessageQueueTemplate send and receive operations to a transactional queue.

Service layer operations that are called inside the message listener will typically be transactional based on using standard Spring declarative transaction management functionality. In case of exceptions in the service layer, the database operation will have been rolled back and the IMessageTransactionExceptionHandler that is later invoked should decide to either commit the surrounding local MSMQ based transaction (removing the message from the queue) or to rollback (placing the message back on the queue for redelivery).

The use of a transactional service layer in combination with a container managed MessageQueueTransaction is a powerful combination that can be used to achieve "exactly one" transaction message processing with database operations that are commonly associated with using transactional messaging and distributed transactions (i.e. both the messaging and database operation commit or rollback together).

The additional programming logic needed to achieve this is to keep track of the Message.Id that has been processed successfully within the transactional service layer. This is needed as there may be a system failure (e.g. power goes off) between the 'inner' database commit and the 'outer' messaging commit, resulting in message redelivery. The transactional service layer needs logic to detect if incoming message was processed successfully. It can do this by checking the database for an indication of successfull processing, perhaps by recording the Message.Id itself in a status table. If the transactional service layer determines that the message has already been processed, it can throw a specific exception for thise case. The container's exception handler will recognize this exception type and vote to commit (remove from the queue) the 'outer' messaging transaction. Spring provides an exception handler with this functionality, see SendToQueueExceptionHandler for more information.

If you specify an implementation of IResourceTransactionManager (e.g. AdoPlatformTransactionManager or HibernateTransactionManager) then an local database transaction will be started before receiving the message. By default, the container will also start a local MessageQueueTransaction after the local database transaction has started, but before the receiving the message. The MessageQueueTransaction will be used to receive the message. If you do not want his behavior set UseContainerManagedMessageQueueTransaction to false. Also by default, the MessageQueueTransaction will be bound to thread local storage such that any MessageQueueTemplate send or recieve operations will participate transparently in the same MessageQueueTransaction. If you do not want this behavior set the property ExposeContainerManagedMessageQueueTransaction to false.

In case of exceptions during IMessageListener processing when using an implementation of IResourceTransactionManager (e.g. and starting a container managed MessageQueueTransaction) the container's IMessageTransactionExceptionHandler will determine if the MessageQueueTransaction should commit (removing it from the queue) or rollback (placing it back on the queue for redelivery). The listener exception will always trigger a rollback in the 'outer' (e.g. AdoPlatformTransactionManager or HibernateTransactionManager) based transaction.

PoisonMessage handing, that is endless redelivery of a message due to exceptions during processing, can be detected using implementatons of the IMessageTransactionExceptionHandler interface. A specific implementation is provided that will move the poison message to another queue after a maximum number of redelivery attempts. See SendToQueueExceptionHandler for more information.

Inheritance: Spring.Messaging.Listener.AbstractTransactionalMessageListenerContainer
        public void EnsureuseContainerManagedMessageQueueTransactionIsSetCorrectly()
        {
            TransactionalMessageListenerContainer container = applicationContext["transactionalMessageListenerContainer"] as TransactionalMessageListenerContainer;

            Assert.IsNotNull(container);
            Assert.AreEqual(true, container.UseContainerManagedMessageQueueTransaction);
        }
        public void EnsureMessageQueuePropertyIsSet()
        {
            TransactionalMessageListenerContainer container = new TransactionalMessageListenerContainer();

            try
            {
                container.AfterPropertiesSet();
                Assert.Fail("Expected ArgumentException not thrown.");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("Property 'MessageQueueObjectName' is required", ex.Message);
            }
        }
        public void EnsureMessageQueuePropertyIsSet()
        {
            TransactionalMessageListenerContainer container = new TransactionalMessageListenerContainer();

            try
            {
                container.AfterPropertiesSet();
                Assert.Fail("Expected ArgumentException not thrown.");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("Property 'MessageQueueObjectName' is required", ex.Message);
            }
        }