Reputation: 20758
I've tried MsmqIntergrationBinding and NetMsmqBinding, but I'm struggling to achieve my goal of processing transactional WCF MSMQ partially-ordered messages asynchronously.
I want to use WCF to listen for messages on a transactional queue. To process the message, I demultiplex the incoming message into various (in-memory) Queue<>s based on message contents. The MSMQ Transaction stays open while the message is processed asynchronously but the WCF Dispatcher is free to move ahead with accepting any next message. The Queue<>'d, demultiplexed messages need to contain the handles necessary to commit or rollback the MSMQ Transaction once fully processed. The completion of the WCF callback to Process() the MSMQ should not wait for the asynchronous message to be processed nor should it Commit the transaction before the asynchronous operations are finished. The messages have a partial ordering within "conversations" which should be preserved as it is read from the MSMQ into the Queue<>.
The obstacle is that I cannot figure out how to keep the transaction open without holding up WCF, and I can't figure out how to maintain the partial ordering without single-threading WCF. If I can maintain the transaction but release a single-threaded WCF dispatcher to move on the the next msmq.Receive() once I've merely Queue<>'d the item in memory (with it's open transaction) I think I'd be OK.
I've tried turning TransactionAutoComplete = false, but that had a nasty chain of consequences, including forcing InstanceContextMode = PerSession and therefore requiring NetMsmqBinding only which I dislike compared to MsmqIntegrationBinding. Also, I cannot commit the transaction at all unless I have IsTerminating = true on the Process() operation. PerSession seems like an otherwise inappropriate choice anyhow. Yet I remain defeated: If I try to pass around the operationContext = OperationContext.Current
to the asynchronous processing, it seems to lose some important internals because I get errors when I try to operationContext.SetTransactionComplete();
saying there's no transaction to be completed.
[OperationContract(IsOneWay = true, Action = "*", IsTerminating = true)]
void Process(M msg);
I could thread-wait the Process() call by WCF until the async operations signal that they're complete, but that practically requires multi-threaded WCF and kills the partial-ordering requirement.
Ideas?
Upvotes: 2
Views: 814
Reputation: 28698
The obstacle is that I cannot figure out how to keep the transaction open without holding up WCF
That's a problem.
You're specifically dealing with a queue. It's an inherently ordered structure which guarantees "first in, first out". You're dealing with it transactionally, which means that if there's a rollback then a message needs to be put back to the head of the queue.
How can you process a second message in the queue before you've finished with the first - what would happen in the case of a rollback?
Upvotes: 2