Iwork in a fairly large office building with a central mailroom. The existenceof this mailroom greatly simplifies life for both me and the postal serviceemployee who delivers mail to my building. I have a centralized place to pickup my mail, and the mail carrier doesn’t have to hunt around the entirebuilding looking for every individual office. Instead, there’s one guy atmy company whose job is to take the bundle of incoming mail and distribute it tothe mailboxes of each person in the building. In this way, large numbers ofmessages can be delivered to their appropriate recipients quickly, with minimalwork on everyone’s part.
There’s an analogy between an office mailroom and the messaging internalsof WSE2. Both systems, in effect, solve similar problems, and by looking at howone functions it is possible to understand the other.
My office building houses many message destinations (people) within a singlephysical address. The WSE2 analogy of my office building is an application thathosts a set of services. Although this application might host a large number ofservices, it only needs one transport address. For example, many differentservices can be hosted over the same TCP port. One address – many destinations.This is a new notion in WSE2, made possible by WS-Addressing. In ASMX webservices, the concept of “service identity” and “transportaddress” are bound up into a single URI. In other words, the problem oflogically identifying a service is inextricably linked with the problem ofdelivering messages to it. In WSE2, services have an “identity URI”which uniquely identifies the service for things like policy application aswell as a “transport address”, which tells the infrastructure howto get messages from point A to point B. Keeping these two ideas separate isimportant when you start thinking about exposing a service over a variety ofnetwork transports. WSE addresses this separation through theEndpointReference.Via property – the details of which can be found
By the time a letter arrives at my office building, it’s already traveledthrough a complicated infrastructure in order to get from its original senderto my building. From the perspective of my office mail clerk, though, thisprocess “just happens” and he doesn’t have to be concernedabout its internals. All the mail clerk has to do is be familiar enough withthe protocols of the network to transfer messages on and off of it – in thereal world, this means signing USPS delivery confirmations and filling outshipping labels. In the WSE2 analogy, the infrastructure for exchangingmessages with the outside world is implemented using some sort of standardizedmessage exchange technology (e.g. TCP, UDP, SMTP, HTTP, MSMQ, etc). The WSE 2.0“mail clerk” must implement enough of the network protocols to movemessages on and off of the underlying network.
In WSE2, the “mail clerk” is a concrete implementation of theSoapTransport class. Each particular network technology has its ownSoapTransport implementation – WSE2 ships with implementations for TCPand HTTP, and it’s possible to extend the architecture to othertransports by implementing custom derivations of SoapTransport. A SoapTransportimplementation is responsible for maintaining a pool of network resources overwhich messages might arrive. The TCP transport, for example, maintains a set ofTCP sockets in “listen” mode. Similarly, an MSMQ transport mightmaintain a pool of MessageQueue objects. As such, the transport serves as anabstraction barrier between the network and the rest of the messagingarchitecture. It encapsulates the details of the underlying network so thatthey are hidden from higher layers of the messaging stack.
In my office, every person has a mailbox that stores incoming mail until therecipient gets around to picking it up. When the mailman arrives at my officebuilding, he leaves a large bundle of incoming mail with the mail clerk. Themail clerk is responsible for looking at the address of each letter anddelivering it to the proper mailbox. In WSE2, the analogy to “mailbox”is an ISoapInputChannel implementation. An InputChannel is like a mailbox forservices – it stores messages that are addressed to a specific serviceuntil that service can come and pick them up.
The transport class is responsible for the creation and maintenance of inputchannels. Every SoapTransport must implement ISoapTransport.GetInputChannel(EndpointReference epr, SoapChannelCapabilities c ). This method opens an inputchannel on a specific endpoint. As part of the GetInputChannel() operation, thetransport class must open a new network resource (exactly which networkresource is derived from the EndpointReference.TransportAddress property,according to the semantics of the transport). For example, as part of openingan InputChannel on the “soap.tcp://localhost:2323” URI, the TCPtransport might open a TCP socket on port 2323 – but in general it’sup to each individual transport implementation to determine how to maptransport addresses into network resources. The transport must also store thenewly created input channel in an internal collection (conveniently implementedby the SoapTransport.InputChannels collection), so it can deliver messages tothat channel when they arrive later.
Just like the mail clerk, the SoapTransport implementation must look at theaddress of each incoming message and deliver it to the appropriateInputChannel. This operation can be done generically for all transport (thanksto the transport-independent addressing mechanism that WS-Addressing provides).As such, dispatch logic is implemented in a single place – SoapTransport.DispatchMessage().Thus, when a message arrives on a the network, the transport is responsible fordeserializing that message from the network and callingSoapTransport.DispatchMessage(). DispatchMessage() then looks at the addressingheaders of the message and matches them against the all of the activeInputChannels the transport maintains in its InputChannels collection. If amatch is found, dispatch message calls InputChannel.Enqueue to store themessage in the InputChannel.
When a message arrives in my office mailbox, it stays there until I pick it up.Similarly, messages stay buffered in an InputChannel until the service thatopened the channel can come along and process it. Realistically, I don’tthink that messages really accumulate inside of the InputChannel because theservice infrastructure picks them up almost as soon as they come in – butconceptually, the InputChannel offers the same buffering capabilities as a realmailbox.
The problem with my office mailroom is that I periodically have to poll mymailbox for new messages. Being the lazy programmer that I am, what I’dreally like is for an intern to watch my inbox for me and run over to my officewith the new message every time one arrives. WSE2 allows services a similardegree of laziness; the service class (whatever concrete subtype ofSoapReceiver that happens to be) is not responsible for monitoring the statusof its input channels directly. Instead, there’s an intermediary –an intern, if you will, that takes care of delivering the message from theinput channel to the SoapReceiver automatically. This “intern” isthe SoapReceivers collection.
In order to register a listening service, you must register it with theSoapReceivers collection by calling SoapReceivers.Add( EndpointReference epr,SoapReceiver receiver). This binds a service instance to an endpoint and startsthe messaging infrastructure listening for messages on that endpoint. Internally,this is accomplished by finding the appropriate instance of SoapTransport basedupon the URI scheme of the endpoint’s TransportAddress, and then callingGetInputChannel() on that transport. The SoapReceivers collection can then callBeginReceive() on that InputChannel, registering a generic dispatch function asa callback. Thus, whenever a message arrives on that InputChannel, the callbackwill be invoked and the SoapReceivers collection can deliver that message fromthe InputChannel to the waiting service. It’s exactly the same effect ashaving someone run up to your office every time a message arrives in yourmailbox, only it’s accomplished with async callbacks and no interns.
In summary, delivering a message to your office is a series of the followingasynchronous operations:
Thecorresponding sequence of asynchronous events in WSE2 is as follows:
I’lltalk more about what I see as the benefits of this architecture later. I’llalso be talking more about the mechanics of accomplishing all of this via acustom transport implementation in future posts.
