See the Intro to this series, which has links to all the parts.
In Part 1, I talked about how a developer uses the IBus interface to publish or send messages, and the IMessageHandler interface to write message handling code.
How, then, does a message actually get transferred from the process where we call Publish() or SendRequest() to the destination process, frequently on some other machine, and result in a call to the Handle() method?
As I said in the introduction, I was interested in learning about buses with WCF and MSMQ. First, we created a WCF service contract:
To send a message, the implementation of IBus wraps the business message in a new TransportMessage instance, creates a WCF client proxy for the IBusReceiver service, and then calls Receive() or ReceiveInTransaction() on the proxy. (I’ll talk about transactions in detail in the next post.)
The funkiness of calling Receive() in order to send a message is hidden away inside our bus implementation. Developers using the bus don’t use IBusReceiver. They call IBus.Publish() or IBus.SendRequest(), which makes a lot more sense in the context of application code.
Just as in NServiceBus, TransportMessage is a wrapper around the actual business message. It allows us to use the same Receive() method to receive any business message type.
The client is configured with WCF’s NetMsmqBinding. As a result, the Uri to which the proxy sends the message looks like net.msmq://DestinationServer/QueueName. WCF converts the Uri into an MSMQ queue name, and asks MSMQ to deliver the message.
As with all messages in MSMQ, if the destination server is the local machine, the message is directly written to the queue. If the destination server is remote, the message is written into an outgoing queue on the local machine. MSMQ then handles getting the message across the wire to the destination server and writing it to the queue.
All of our applications are IIS-hosted. The Windows Process Activation Service (aka WAS) ties together MSMQ, WCF, and IIS — when a message arrives in a queue, WAS informs IIS that it must start the associated web app process, if it isn’t already.
The Net.Msmq Listener Adapter Service informs WCF that there is a message waiting, so that WCF can spin up the ServiceHost, if necessary, and then pull the message from the queue and pass it to the WCF service’s Receive() method.
The point of all this glue is simply so that an arriving message can start the IIS app pool, site, application, and WCF service. This is all built in to WCF and IIS — we didn’t need to write any code to make all this happen.
The implementation of IBusReceiver.Receive() looks up the message handlers that have been registered for the specific business message type, constructs a MessageHandlingContext object containing the inbound message, and then for each registered handler type, constructs a new instance and calls its Handle() method. I’ll talk about how message handlers get registered in a future post.
In Part 3, I’ll talk about transactions.